手写Android事件分发
2019-06-16 23:53
1736 查看
手写Android事件分发
Android
事件分发原理
搞清楚可以辅助我们解决很多实际项目中遇到的
事件冲突等问题
进入正题之前,问大家几个事件相关的问题?
Q:
1、Android事件分发类型有哪几个状态
A:onTouchDown,onTouchMove,onTouchCancel,onTouchUp
Q:
2、Android点击事件传递规则是怎样的?
下面这段话仔细阅读2遍,有助于加深对事件传递的理解
A:当点击事件产生后,会由
Activity来处理,传递给
PhoneWindow,再传递给
DecorView,最后传递给顶层的
ViewGroup。对于根
ViewGroup,点击事件首先传递给它的
dispatchTouchEvent()方法,如果该
ViewGroup的
onInterceptTouchEvent()方法返回true,则表示它要拦截这个事件,这个事件就会交给它的
onTouchEvent()方法处理。如果
onInterceptTouchEvent()方法返回
false,则表示它不拦截这个事件,则这个事件会交给它的子元素的
dispatchTouchEvent()来处理,如此反复下去。如果传递给底层的View,View是没有子View的不再需要拦截了,就会调用View的
dispatchTouchEvent()方法,一般情况下最终会调用View的
onTouchEvent()方法。接下来讲解点击事件由下而上的传递。当点击事件传给底层的 View 时,如果其
onTouchEvent()方法返回
true,则事件由底层的View消耗并处理;如果返回
false则表示该View不做处理,则传递给父View的
onTouchEvent()处理;若父View的
onTouchEvent()仍旧返回false,则继续传递给该父View的父View处理,如此反复下去
Q:
3、requestDisallowInterceptTouchEvent属性的作用?
A:禁止或允许父View拦截自己的点击事件
// 不允许父View 拦截点击事件 // false则反之 getParent().requestDisallowInterceptTouchEvent(true);
以下通过Java层代码模拟Android中事件分发流程,有助于理解Android事件分发机制,希望能帮助到大家(创建6个java文件,然后以java工程运行打印日志学习)
如果你能静下心来,读完下面6个.java文件代码,我相信你能收获很多
假Activity
public class Activity { public static void main(String[] arg) { // 顶级容器ViewGroup(构造函数传递左上,右下坐标) ViewGroup viewGroup = new ViewGroup(0, 0, 1080, 1920); viewGroup.setName("顶级容器"); // 二级容器ViewGroup,也是定义两个坐标 ViewGroup viewGroup1 = new ViewGroup(0, 0, 500, 500); viewGroup1.setName("第二级容器"); // 模拟初始化View以及放置在ViewGroup层级中 View view = new View(0, 0, 200, 200); view.setName("子View"); viewGroup1.addView(view); viewGroup.addView(viewGroup1); viewGroup.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { System.out.println("顶级的OnTouch事件"); return false; } }); viewGroup1.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { System.out.println("第二级容器的OnTouch事件"); return false; } }); // view.setOnClickListener(new OnClickListener() { // @Override // public void onClick(View v) { // System.out.println("子iew的onClick事件"); // } // }); // view.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { System.out.println("子view的OnTouch事件"); return false; } }); // 模拟事件分发(点击里面View坐标点为:(100,100)) MotionEvent motionEvent = new MotionEvent(100, 100); motionEvent.setActionMasked(MotionEvent.ACTION_DOWN); // 顶级容器分发 viewGroup.dispatchTouchEvent(motionEvent); } }
假ViewGroup
public class ViewGroup extends View { // 子View个数 private View[] mChildren = new View[0]; public ViewGroup(int left, int top, int right, int bottom) { super(left, top, right, bottom); } List<View> childList = new ArrayList<>(); public void addView(View view) { if (view == null) { return; } childList.add(view); mChildren = childList.toArray(new View[childList.size()]); } private TouchTarget mFirstTouchTarget; // 事件分发的入口 public boolean dispatchTouchEvent(MotionEvent event) { // System.out.println(name + " dispatchTouchEvent "); boolean handled = false; boolean intercepted = onInterceptTouchEvent(event); // TouchTarget 模式 内存缓存 move up TouchTarget newTouchTarget = null; int actionMasked = event.getActionMasked(); if (actionMasked != MotionEvent.ACTION_CANCEL && !intercepted) { // 不拦截情况下,开始处理Down事件 if (actionMasked == MotionEvent.ACTION_DOWN) { final View[] children = mChildren; // 遍历ViewGroup中所有子View for (int i = children.length - 1; i >= 0; i--) { View child = mChildren[i]; // View能够接收到事件 if (!child.isContainer(event.getX(), event.getY())) { continue; } // 能够接受事件 child 分发给他 if (dispatchTransformedTouchEvent(event, child)) { // View[] 采取了 Message 的方式进行 链表结构 handled = true; newTouchTarget = addTouchTarget(child); break; } } } // 当前的ViewGroup dispatchTransformedTouchEvent if (mFirstTouchTarget == null) { handled = dispatchTransformedTouchEvent(event, null); } } return handled; } private TouchTarget addTouchTarget(View child) { final TouchTarget target = TouchTarget.obtain(child); target.next = mFirstTouchTarget; mFirstTouchTarget = target; return target; } // 回收池策略· private static final class TouchTarget { public View child;//当前缓存的View // 回收池(一个对象) private static TouchTarget sRecycleBin; private static final Object sRecycleLock = new Object[0]; public TouchTarget next; // size private static int sRecycledCount; // up事件 public static TouchTarget obtain(View child) { TouchTarget target; synchronized (sRecycleLock) { if (sRecycleBin == null) { target = new TouchTarget(); } else { target = sRecycleBin; } sRecycleBin = target.next; sRecycledCount--; target.next = null; } target.child = child; return target; } public void recycle() { if (child == null) { throw new IllegalStateException("已经被回收过了"); } synchronized (sRecycleLock) { if (sRecycledCount < 32) { next = sRecycleBin; sRecycleBin = this; sRecycledCount += 1; } } } } //分发处理 子控件 View private boolean dispatchTransformedTouchEvent(MotionEvent event, View child) { boolean handled = false; // 当前View消费了 if (child != null) { handled = child.dispatchTouchEvent(event); } else { handled = super.dispatchTouchEvent(event); } return handled; } /** * @param ev * @return 是否拦截点击事件 */ public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } }
假View
public class View { public String name; @Override public String toString() { return "" + name; } public void setName(String name) { this.name = name; } private int left; private int top; private int right; private int bottom; private OnTouchListener mOnTouchListener; private OnClickListener onClickListener; public void setOnTouchListener(OnTouchListener mOnTouchListener) { this.mOnTouchListener = mOnTouchListener; } public void setOnClickListener(OnClickListener onClickListener) { this.onClickListener = onClickListener; } public View() { } public View(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } /** * @param x * @param y * @return 是否处于View点击区域内 */ public boolean isContainer(int x, int y) { if (x >= left && x < right && y >= top && y < bottom) { return true; } return false; } // 接受分发的代码 public boolean dispatchTouchEvent(MotionEvent event) { System.out.println(name + " dispatchTouchEvent "); // 消费 boolean result = false; if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; } return result; } private boolean onTouchEvent(MotionEvent event) { System.out.println(name + " onTouchEvent "); if (onClickListener != null) { onClickListener.onClick(this); return true; } return false; } }
假MotionEvent
public class MotionEvent { public static final int ACTION_DOWN = 0; public static final int ACTION_UP = 1; public static final int ACTION_MOVE = 2; public static final int ACTION_CANCEL = 3; private int actionMasked; private int x; private int y; public MotionEvent() { } public MotionEvent(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getActionMasked() { return actionMasked; } public void setActionMasked(int actionMasked) { this.actionMasked = actionMasked; } }
假OnClickListener
public interface OnClickListener { void onClick(View v); }
假OnTouchListener
public interface OnTouchListener { boolean onTouch(View v, MotionEvent event); }
参考
相关文章推荐
- android ViewGroup事件分发源码解析
- Android View 事件分发源码分析
- android touch事件分发、拦截和响应分析
- Android 编程下 Touch 事件的分发和响应机制 分类: Android 2015-07-02 17:35 12人阅读 评论(0) 收藏
- Android里的onTouch事件的分发与消费
- Android View 点击事件的分发机制
- 图解 Android 事件分发机制
- Android:View事件分发机制详解
- android_事件分发相关,看这两篇文章,就足够
- android开发艺术探索事件分发总结
- Android 事件分发 简单学
- Android 应用及窗体事件的分发
- android 事件分发机制详解(最简单的解释)
- android事件分发机制的再学习
- Android 编程下 Touch 事件的分发和消费机制
- android 的事件分发从源码分析
- Android事件分发机制
- android触摸事件的分发机制、冒泡机制、消费机制
- Android View的事件分发机制探索
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)