《Android開發(fā)藝術(shù)探索》——View事件體系

自定義控件、滑動沖突解決

View基礎(chǔ)知識

  1. View的位置參數(shù)
  2. MotionEvent和TouchSlop對象
  3. VelocityTracker
  4. GestureDetector和Scroller對象

1. View的位置參數(shù)

[圖片來源](http://blog.csdn.net/jason0539/article/details/42743531)
[圖片來源](http://blog.csdn.net/jason0539/article/details/42743531)

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);

接管目標ViewonTouchEvent方法,在待監(jiān)聽ViewonTouchEvent方法中添加如下實現(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為正值,反之為負值。

getScrollX和getScrollY的變化示意圖

參考鏈接:
Android Scroller完全解析,關(guān)于Scroller你所需知道的一切 - 郭霖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容