編輯:關於Android編程
通過不斷重新layout view 達到滑動的效果。
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 記錄觸摸點坐標 lastX = x; lastY = y; break; case MotionEvent.ACTION_MOVE: // 計算偏移量 int offsetX = x - lastX; int offsetY = y - lastY; // 在當前left、top、right、bottom的基礎上加上偏移量 layout(getLeft() + offsetX,getTop() + offsetY,getRight() + offsetX,getBottom() + offsetY); //與上面的方法是等效,直接設置偏移量 //offsetLeftAndRight(offsetX); //offsetTopAndBottom(offsetY); break; } return true; }
這裡需要注意,我們使用的getX 和getY 方法,如果使用 getRawX 和getRawY 方法,那麼代碼就要做些許改變。就是在重新layout後,我們需要重新賦值 lastX和lastY的值。 否則就會出現意想不到的結果哦。 有興趣的朋友可以試一試,可以加深對於這兩個方法的認識。
–
layoutparams 保存了view的布局參數,我們可以通過不斷修改其參數,重新設置,達到滑動效果。需要修改的參數就是自己與父view的邊距。注意通過getLayotParams 方法獲取layoutparams時類型要根據其父view的類型來確定。
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 記錄觸摸點坐標 lastX = (int) event.getX(); lastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: // 計算偏移量 int offsetX = x - lastX; int offsetY = y - lastY; // 轉換成這個類型,就不用關心父view的類型了 ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); //LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams(); layoutParams.leftMargin = getLeft() + offsetX; layoutParams.topMargin = getTop() + offsetY; setLayoutParams(layoutParams); break; } return true; }
–
srollTo(x,y) 表示移動到位置(x,y)處。
srollBy(dx,dy) 表示在當前位置的基礎上移動 dx和dy的距離。dx和dy為偏移量。
public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
同時需要注意,他們移動的都是view自己的內容。對應 viewgroup移動的就是自己的子view。所以父viewgroup中的素有view都會一起移動哦。
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getX(); lastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int offsetX = x - lastX; int offsetY = y - lastY; //這裡要注意,offsetx為我們相對於父viewgroup移動的距離,但是,這裡我們調用的是讓父viewgroup移動的方法,所以參考系,相對於反轉了,所以要在前面加上負號。 ((View) getParent()).scrollBy(-offsetX, -offsetY); break; } return true; }
–
與上面的不同,scroller主要是用於當沒有用戶手動操作的時候,我們用來連續移動 view 的方式。需要配合view 的computeScroll 和scrollTo方法配合使用。該方法會在view 的draw方法中被調用。
@Override public void computeScroll() { super.computeScroll(); // 判斷Scroller是否執行完畢 if (mScroller.computeScrollOffset()) { ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // 通過重繪來不斷調用computeScroll invalidate(); } } @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getX(); lastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int offsetX = x - lastX; int offsetY = y - lastY; ((View) getParent()).scrollBy(-offsetX, -offsetY); break; case MotionEvent.ACTION_UP: // 手指離開時,執行滑動過程 View viewGroup = ((View) getParent()); mScroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY()); invalidate(); break; } return true; }
流程如下:
說的通俗一點就是:scroller 每次提供一個值 mScroller.getCurrX(),然後view scrollTo這個位置,然後view 重新繪制,然後又調用 computeScroll 方法,然後scroler 又提供一個值mScroller.getCurrX() 又重繪。 相當於一個死循環,不停地移動。 循環的出口就是mScroller.computeScrollOffset() 方法。 這個方法有兩個作用,一個是返回是否滑動到了指定的位置,二是每次調用時會不斷的改變 mScroller.getCurrX()的值,讓這個越來越接近滑動結束的值,知道達到滑動結束的值時,該方法的返回值也就變成了false。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPr+0v7RzY3JvbGxlcrXEsr+31rT6wuujrMrXz8jKx8bkubnU7Lqvyv2jrMbkyrXSsr7Nysez9cq8u6/By9K70Km7rLavtcTOu9bDus3Ksbzk1rWjujwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> public void startScroll(int startX, int startY, int dx, int dy, int duration) { mMode = SCROLL_MODE; mFinished = false; mDuration = duration; mStartTime = AnimationUtils.currentAnimationTimeMillis(); mStartX = startX; mStartY = startY; mFinalX = startX + dx; mFinalY = startY + dy; mDeltaX = dx; mDeltaY = dy; mDurationReciprocal = 1.0f / (float) mDuration; // This controls the viscous fluid effect (how much of it) mViscousFluidScale = 8.0f; // must be set to 1.0 (used in viscousFluid()) mViscousFluidNormalize = 1.0f; mViscousFluidNormalize = 1.0f / viscousFluid(1.0f); }
然後是其 computeScrollOffset()方法
public boolean computeScrollOffset() { if (mFinished) { return false; } int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); if (timePassed < mDuration) { switch (mMode) { case SCROLL_MODE: float x = (float)timePassed * mDurationReciprocal; if (mInterpolator == null) x = viscousFluid(x); else x = mInterpolator.getInterpolation(x); mCurrX = mStartX + Math.round(x * mDeltaX); mCurrY = mStartY + Math.round(x * mDeltaY); break; case FLING_MODE: float timePassedSeconds = timePassed / 1000.0f; float distance = (mVelocity * timePassedSeconds) - (mDeceleration * timePassedSeconds * timePassedSeconds / 2.0f); mCurrX = mStartX + Math.round(distance * mCoeffX); // Pin to mMinX <= mCurrX <= mMaxX mCurrX = Math.min(mCurrX, mMaxX); mCurrX = Math.max(mCurrX, mMinX); mCurrY = mStartY + Math.round(distance * mCoeffY); // Pin to mMinY <= mCurrY <= mMaxY mCurrY = Math.min(mCurrY, mMaxY); mCurrY = Math.max(mCurrY, mMinY); break; } } else { mCurrX = mFinalX; mCurrY = mFinalY; mFinished = true; } return true; }
ViewDragHelper是
v4包中Google 為我們封裝了
Scroller的一個工具類。為我們實現不同的滑動等效果提供的一種方案。
其一般使用在ViewGroup中,通過其工廠方法創建其實例,通過其實例來處理
View的事件和移動。 相當於我們把
View(子
View)都交給她來處理了。
首先當然是先創建其實例對象
mViewDragHelper = ViewDragHelper.create(this, callback);
將ViewGroup的事件交給mViewDragHelper處理
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
因為同樣是 通過Scroller實現滑動的,所以我們也需要重寫computeScroll方法
@Override
public void computeScroll() {
if (mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
這些也都是固定寫法了。
最為關鍵的就是 在創建mViewDragHelper時我們傳入的callback對象,這個是我們要自己去實現的。通過這個回調,我們可以實現我們自己需要的滑動效果。
private ViewDragHelper.Callback callback =
new ViewDragHelper.Callback() {
//是否處理 該view也就是參數 child。返回 true 處理,否則這忽略噶子view。
@Override
public boolean tryCaptureView(View child, int pointerId) {
return mchild == child;
}
// 觸摸到View後回調
@Override
public void onViewCaptured(View capturedChild,
int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
// 當拖拽狀態改變時回調 如:STATE_IDLE、STATE_DRAGGING、STATE_SETTLING
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
}
// 當位置改變的時候調用,常用與滑動時更改scale等
@Override
public void onViewPositionChanged(View changedView,
int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
}
// 處理垂直滑動
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
// 處理水平滑動
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
// 拖動結束後調用
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
//手指抬起後緩慢移動到指定位置
//相當於Scroller的startScroll方法
mViewDragHelper.smoothSlideViewTo(mchild, 0, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
};
這樣,我們就完成了想要的滑動了。之後,會分析一下它的源碼,看看到底如何實現的。
你的AndroidStudio編譯時是否很卡?你的Gradle編譯時是否很慢,運行一次要等10分鐘?如果你還沒有遇到,那可能說明你的電腦配置夠好,或者項目還不夠大。尤其像
Android中的動畫分為視圖動畫(View Animation)、屬性動畫(Property Animation)以及Drawable動畫。Android從最初的版本就
單純使用GridView通用的兩種給GridView 添加分割線的方法;http://stackoverflow.com/questions/7132030/androi
在android上發送郵件方式: 第一種:借助GMail APP客戶端,缺點是必須使用GMail帳號,有點是比較方便 不需要寫很多代碼,但是不是很靈活。 第