事件体系里, 除《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. 使用延时策略
来源: https://juejin.im/post/5c176bb6f265da61137f2f23