事件体系里,除《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…
结言
很多内容是未完成的,感到很尴尬,有时间再补充吧,捂脸。