Android事件分发机制二
来源:互联网 发布:山东双轨直销软件 编辑:程序博客网 时间:2024/05/22 12:13
创建Demo
MainActivity.java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化控件 MyLinearLayout mgLayout = (MyLinearLayout) findViewById(R.id.mylayout); Button btn = (Button) findViewById(R.id.btn); //添加onClick事件 mgLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.i("chuyibo","点击了自定义线性布局MyLinearLayout"); } }); //添加onClick事件 btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.i("chuyibo","点击了btn"); } }); }}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><bo.yi.chu.chuyibo2.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mylayout" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="#fff"> <Button android:layout_width="150dp" android:layout_height="50dp" android:id="@+id/btn" android:background="#684132" android:text="点击" android:textSize="16sp" android:textColor="#fff"/></bo.yi.chu.chuyibo2.MyLinearLayout>
MyLinearLayout.java
public class MyLinearLayout extends LinearLayout { public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return false; }}
运行
点击Button查看Log日志
点击空白区域查看Log日志
查看日志得出结论,myLayout为btn的父类,两者同时添加onClick监听,点击btn,只有btn的onClick()方法执行。点击myLayout(空白区域)只有myLayout的onClick()方法执行,Demo中MyLinearLayout继承LinearLayout,并重写了onInterceptTouchEvent()。
onInterceptTouchEvent()方法中有一个返回值,Demo中的返回值为false。把该方法的返回值改为true,重新点击Button和空白区域查看Log日志。
public boolean onInterceptTouchEvent(MotionEvent ev) { return true;//返回值改为true}
点击Button查看Log日志
点击空白区域查看Log日志
查看日志得出结论,当onInterceptTouchEvent()方法返回true时,无论点击btn还是myLayout,都只执行myLayout的onClick()方法。
android中的布局直接或者间接的继承了ViewGroup,ViewGroup又是View的子类,但是ViewGroup重写了dispatchTouchEvent()方法。ViewGroup中可以存放多个View,当点击一个ViewGroup中的子View时触摸事件是先传递给了ViewGroup,然后有ViewGroup的dispatchTouchEvent()分发给子View,最后再有子View的dispatchTouchEvent()来处理触摸事件。同时ViewGroup也可以拦截事件从而使触摸事件不传递给子View,onInterceptTouchEvent()方法就是事件传递的拦截器。
源码分析
dispatchTouchEvent()
public boolean dispatchTouchEvent(MotionEvent ev) { final int action = ev.getAction(); final float xf = ev.getX(); final float yf = ev.getY(); final float scrolledXFloat = xf + mScrollX; final float scrolledYFloat = yf + mScrollY; final Rect frame = mTempRect; boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (action == MotionEvent.ACTION_DOWN) { if (mMotionTarget != null) { // this is weird, we got a pen down, but we thought it was // already down! // XXX: We should probably send an ACTION_UP to the current // target. mMotionTarget = null; } // If we're disallowing intercept or if we're allowing and we didn't // intercept if (disallowIntercept || !onInterceptTouchEvent(ev)) { // reset this event's action (just to protect ourselves) ev.setAction(MotionEvent.ACTION_DOWN); // We know we want to dispatch the event down, find a child // who can handle it, start with the front-most child. final int scrolledXInt = (int) scrolledXFloat; final int scrolledYInt = (int) scrolledYFloat; final View[] children = mChildren; final int count = mChildrenCount; for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(scrolledXInt, scrolledYInt)) { // offset the event to the view's coordinate system final float xc = scrolledXFloat - child.mLeft; final float yc = scrolledYFloat - child.mTop; ev.setLocation(xc, yc); if (child.dispatchTouchEvent(ev)) { // Event handled, we have a target now. mMotionTarget = child; return true; } // The event didn't get handled, try the next view. // Don't reset the event's location, it's not // necessary here. } } } } } boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) || (action == MotionEvent.ACTION_CANCEL); if (isUpOrCancel) { // Note, we've already copied the previous state to our local // variable, so this takes effect on the next event mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; } // The event wasn't an ACTION_DOWN, dispatch it to our target if // we have one. final View target = mMotionTarget; if (target == null) { // We don't have a target, this means we're handling the // event as a regular view. ev.setLocation(xf, yf); return super.dispatchTouchEvent(ev); } // if have a target, see if we're allowed to and want to intercept its // events if (!disallowIntercept && onInterceptTouchEvent(ev)) { final float xc = scrolledXFloat - (float) target.mLeft; final float yc = scrolledYFloat - (float) target.mTop; ev.setAction(MotionEvent.ACTION_CANCEL); ev.setLocation(xc, yc); if (!target.dispatchTouchEvent(ev)) { // target didn't handle ACTION_CANCEL. not much we can do // but they should have. } // clear the target mMotionTarget = null; // Don't dispatch this event to our own view, because we already // saw it when intercepting; we just want to give the following // event to the normal onTouchEvent(). return true; } if (isUpOrCancel) { mMotionTarget = null; } // finally offset the event to the target's coordinate system and // dispatch the event. final float xc = scrolledXFloat - (float) target.mLeft; final float yc = scrolledYFloat - (float) target.mTop; ev.setLocation(xc, yc); return target.dispatchTouchEvent(ev); }
第21行是一个if判断,disallowIntercept表示是否禁止掉拦截事件的功能,默认为false,因此if判断为true或false取决于onInterceptTouchEvent()方法的返回值。
onInterceptTouchEvent()方法返回false表示不拦截事件。if条件判断成立,在第30行对ViewGroup中的子View进行遍历,并在第35行进行判断当前子View是否是正在点击的View。如果是,执行View的dispatchTouchEvent()。因为View的dispatchTouchEvent()方法始终返回true,所以40行if条件判断成立,执行return,后面的代码不执行。
onInterceptTouchEvent()方法返回true表示拦截事件,if条件判断不成立。或ViewGroup中没有子View,以及ViewGroup中的所有子View都不是当前正在点击的View时执行后面的语句。第66行判断target是否为null。target一般不会为null,执行第70行super.dispatchTouchEvent()就是调用父类View中的dispatchTouchEvent()方法。
流程图
- Android事件分发机制二
- Android View、ViewGroup 事件分发机制(二)
- Android事件分发机制--ViewGroup(二)
- Android事件分发机制--ViewGroup(二)
- Android事件分发机制完全解析(二)
- Android的事件分发机制(二)
- android-----事件分发机制测试系列(二)
- android事件分发机制解析(二)
- Android事件分发机制详解(二)
- Android----View事件分发机制(二)
- Android事件分发机制(二)
- Android事件分发机制--ViewGroup(二)
- android 事件分发机制详解(二)
- Android事件分发机制(二)
- android事件分发机制
- Android事件分发机制
- Android 事件分发机制
- Android事件分发机制
- JavaScript 跨域访问的问题和解决过程
- calico iptables详解
- 小明的调查作业
- Linux中安装numpy,scipy,matplotib,opencv等函数库
- HTTP 2.0 Client & HTTP 2.0 Server & HTTP 2.0 Proxy
- Android事件分发机制二
- MongoDB(3)——Index的创建流程1
- <1>炫彩界面库源码分析---简单的应用程序过程分析
- phpexcel中文教程-设置表格字体颜色背景样式、数据格式、对齐方式、添加图片、批注、文字块、合并拆分单元格、单元格密码保护
- 用js语句实现网页中的选项卡(两种方法)
- Linux驱动中断函数参数详解
- STM32F407VG discovery MB997B 的串口问题
- C++中使用宏需要注意的规范
- MongoDB优化