自定義控件、滑動沖突解決
View基礎(chǔ)知識
- View的位置參數(shù)
- MotionEvent和TouchSlop對象
- VelocityTracker
- GestureDetector和Scroller對象
1. View的位置參數(shù)
](http://www.wfuyu.com/uploadfile/cj/20150117/20150115155321445.png)
2. MotionEvent和TouchSlop
注意:各個方法相對目標不一樣。
view獲取自身坐標:getLeft(),getTop(),getRight(),getBottom()
view獲取自身寬高:getHeight(),getWidth()
motionEvent獲取坐標:getX(),getY(),getRawX(),getRawY()
- MotionEvent
Touch事件中,典型的事件有如下幾種: - ACTION_DOWN —— 手指接觸屏幕
- ACTION_MOVE —— 手指在屏幕上移動
- ACTION_UP —— 手指從屏幕離開
- TouchSlop
TouchSlop是系統(tǒng)所能識別出的被認為是滑動的最小距離,換句話說,當手指在屏幕上滑動時,當兩次滑動之間的距離小于這個常量,那么系統(tǒng)不認為是在進行滑動操作。通過以下方式獲取這個常量值:
ViewConfiguration.get(getContext()).getScaledTouchSlop();
這個常量有神馬意義呢?
可以使用這個常量判斷是否達到滑動條件,處理滑動時,做一些過濾。
3. VelocityTracker、GestureDetector和Scroller對象
- VelocityTracker
速度追蹤,用于追蹤手指在滑動過程中的速度,包括水平和豎直方向的速度。
構(gòu)造方法中初始化獲取VelocityTracker對象
VelocityTracker mVelocityTracker = VelocityTracker.obtain();
在onTouchEvent方法中添加追蹤事件
mVelocityTracker.addMovement(event);
在ACTION_UP事件中獲取當前的速度。注意這里計算的是1000ms時間間隔移動的像素值,假設像素是100,即速度是每秒100像素。手指從右向左滑動,速度為負值。
mVelocityTracker.computeCurrentVelocity(1000);
float xVelocity = mVelocityTracker.getXVelocity();
float yVelocity = mVelocityTracker.getYVelocity();
最后,當不需要它的時候需要調(diào)用clear方法來重置并回收內(nèi)存。
mVelocityTracker.clear();
mVelocityTracker.recycle();
- GestureDetecor
手勢檢測,用于輔助檢測用戶的單擊、滑動、長按、雙擊等行為。
創(chuàng)建一個GestureDetecor對象并實現(xiàn)OnGestureListener接口,根據(jù)需要實現(xiàn)單擊等方法:
GestureDetector mGestureDetector = new GestureDetector(this);
// 解決長按屏幕后無法拖動的現(xiàn)象
mGestureDetector.setIsLongpressEnabled(false);
接管目標View的onTouchEvent方法,在待監(jiān)聽View的onTouchEvent方法中添加如下實現(xiàn):
boolean consume = mGestureDetector.onTouchEvent(event);
return consume;
建議:
如果只是監(jiān)聽滑動操作,建議在onTouchEvent中實現(xiàn);如果要監(jiān)聽雙擊這種行為,則使用GestureDetector 。
- Scroller
彈性滑動對象,用于實現(xiàn)View的彈性滑動。
View的scrollTo/scrollBy方法來滑動時,過程是瞬間完成的。使用Scroller則有過渡滑動的效果。注意,Scoller本身無法讓View彈性滑動,它需要和View的computerScroller方法配合使用。
構(gòu)造方法初始化
Scroller mScroller = new Scroller(getContext());
緩慢滑動到指定位置,一般在ACTION_UP 方法中執(zhí)行,松手回彈效果。
private void smoothScrollBy(int dx, int dy) {
mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
Scroller原理

當在MotionEvent.ACTION_UP事件觸發(fā)時,調(diào)用startScroll方法,并調(diào)用invalidate/postInvalidate方法,會導致View重繪,執(zhí)行View.draw方法。在此方法中會調(diào)用View.computeScroll方法,此方法是空實現(xiàn),需要我們自己處理邏輯。具體邏輯是:先判斷computeScrollOffset,如果為true,表示滾動未結(jié)束。則執(zhí)行scrollTo方法,再次調(diào)用postInvalidate,如此反復執(zhí)行,直到結(jié)束。
computeScrollOffset方法計算了一小段時間間隔內(nèi)偏移的距離,即CurrX,CurrY。并返回是否滾動結(jié)束的標記。true表示未結(jié)束,false表示結(jié)束。
View的scrollTo/scrollBy方法操作的View的內(nèi)容滑動。
getScrollX返回的是View的左邊緣到其內(nèi)容左邊緣的距離。相對于View的左邊緣
getScrollY返回的是View的上邊緣到其內(nèi)容上邊緣的距離。
如果View的內(nèi)容向左滑,滑出View的左邊界,getScrollX為正值,反之為負值。
如果View的內(nèi)容向上滑,滑出View的上邊界,getScrollY為正值,反之為負值。
