Android View 的事件體系
事件體系裡,除《Android 事件分發機制》這部分內容,是較深入研究了原始碼後總結整理出來的。
其餘內容基本都是閱讀《Android 開發藝術探索》(任玉剛 著)這本書後整理的筆記,內容估計和書上差別不大,已經閱讀過書籍的,可以不用閱讀了,有興趣的可以看看《事件分發機制》那篇部落格,那篇要比書上講解的要深入許多。
為了配合《事件分發機制》那篇部落格,所以這篇部落格沒寫完就發出來了,距離完整版可能還會延期 N 久,捂臉。
前言
文章重點內容為:事件分發機制、滑動衝突解決
目錄(相容稀土掘金)
- 一、View 的位置引數
- 二、MotionEvent 和 TouchSlop
- 三、事件分發機制(另一篇部落格)
- 三個重要方法
- 事件分發機制簡略過程圖
- 從 Activity 到 View 的事件傳遞過程(簡略)
- View 的事件傳遞
- ViewGroup 的事件傳遞
- 從 Activity 到 View 的事件傳遞過程(完整)
- 四、
一、View 的位置引數
位置引數都是相對父容器的座標。座標單位都是 pixel,可歸類為以下三類:
- View 的原始左上角(left, top)、右下角(right, bottom)的座標決定 View 的位置
- View 的左上角座標(x, y)
- translationX、translationY 表示 View 的左上角相對父容器的偏移量
區別
View 在平移的過程中,top、left 表示原始左上角的座標,其值不會發生改變。此時該改變的是x、y、translationX、translationY Android 3.0 開始,才追加 x、y、translationX、translationY
它們的轉換規則為
x = left + translationX
y = top + translationY
複製程式碼
相關API
getTop()
getBottom()
getLeft()
getRight()
getX()
getY()
getTranslationX()
getTranslationY()
複製程式碼
二、MotionEvent 和 TouchSlop
- MotionEvent
表示手指觸控式螢幕幕所產生的一系列事件。型別有:
final int ACTION_DOWN = 0; // 典型事件
final int ACTION_UP = 1; // 典型事件
final int ACTION_MOVE = 2; // 典型事件
final int ACTION_CANCEL = 3;
final int ACTION_OUTSIDE = 4;
final int ACTION_POINTER_DOWN = 5; // 貌似是多滑鼠操作
final int ACTION_POINTER_UP = 6;
final int ACTION_HOVER_MOVE = 7;
final int ACTION_SCROLL = 8;
final int ACTION_HOVER_ENTER = 9; // 滑鼠懸浮
final int ACTION_HOVER_EXIT = 10;
final int ACTION_BUTTON_PRESS = 11; // 按鈕按下
final int ACTION_BUTTON_RELEASE = 12; // 按鈕釋放
複製程式碼
相關API
// 獲取滑鼠座標:相對當前 View 的左上角的 x 和 y 座標
getX()
getY()
// 獲取滑鼠座標:獲取相對手機螢幕的左上角的 x 和 y 座標
getRawX()
getRawY()
複製程式碼
- TouchSlop:最小滑動距離
TouchSlop 是系統所能識別出的被認為是滑動的最小距離。即當手指在手機螢幕上的滑動距離小於該值時,那麼系統不認為你在進行滑動操作。預設最小值為 8dp。
定義檔案路徑:framewoks/base/core/res/res/values/config.xml
相關API
ViewConfiguration.get(context).getScaledTouchSlop();
複製程式碼
三、事件分發機制(另一篇部落格)
詳細內容見部落格《Android View 的事件體系 -- 事件分發機制》,連結見文章頭部
四、滑動衝突
同樣包含在部落格《Android View 的事件體系 -- 事件分發機制》中了
下面的內容基本可以不用看了,捂臉
VelocityTracker
GestureDetector
Scroller
五、View 的滑動
實現 View 的滑動有三種方法:
- 通過 View 本身提供的 scrollTo()、scrollBy()
- 通過動畫給 View 施加平移效果
- 通過改變 View 的 位置引數或 LayoutParams 使得 View 重新佈局來實現滑動
1. scrollTo()、scrollBy() 實現滑動
這兩個方法都是將 View 內容進行移動,並不是將 View 本身進行移動。它們的具體實現如下:
/**
* View 類
*/
/**
* @param x 水平方向的偏移量,單位 pixel
* @param y 垂直方向的偏移量,單位 pixel
*/
public void scrollTo(int x, int y) {
// mScrollX: 表示 View 左邊緣與 View 內容左邊緣的水平方向的距離,單位 pixel
// mScrollY: 表示 View 上邊緣與 View 內容上邊緣的垂直方向的距離,單位 pixel
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
複製程式碼
2. 平移動畫實現滑動
具體實現不多說。View 動畫是對 View 的影像做操作,並不會真正改變 View 的位置引數。如果希望改變 View 的位置引數,則可以通過屬性動畫實現。
3. 改變位置引數或 LayoutParams 實現滑動
改變的是 View 本身的位置引數或 LayoutParams。有兩種方法實現:
- 修改 View 的 marginLeft 等引數實現
- 在 View 的反向位置放置一個空白 View。通過修改空白 View 的寬高實現。
參考程式碼:
// 改變 LayoutParams 引數
MarginLayoutParams mlp = (MarginLayoutParams) button.getLayoutParams();
mlp.leftMargin += 100; // 方法一
mlp.width += 100; // 方法二
button.requestLayout(); // 或 button.setLayoutParams(mlp);
// 改變位置引數
button.setTranslationX(50); // 方法一
button.setTranslationY(50); // 方法一
複製程式碼
4. 三種方法對比
總結如下:
- scrollTo()、scrollBy():操作簡單,適合對 View 內容的滑動
- 動畫:操作簡單,適用於沒有互動的 View 和實現複雜動畫效果
- 改變 LayoutParams:操作稍微複雜,適用於有互動的 View
六、彈性滑動
TODO 待補充
1. 使用 Scroller
2. 使用動畫
3. 使用延時策略
參考
- 《Android 開發藝術探索》(任玉剛 著) 第三章 View 的事件體系
- Android 21 原始碼(主要)
版本
- 2017-12-17:未完成版本
宣告
限於作者水平有限,出錯難免,請積極拍磚! 歡迎任何形式的轉載,轉載請保留本文原文連結:juejin.im/post/5c176b…
結言
很多內容是未完成的,感到很尷尬,有時間再補充吧,捂臉。