在安卓开发中,总是会遇到一些事件冲突的问题,说句实话,我一直也是似懂非懂的状态,理解的也不是很透彻,今天就专门学习了一下这方面的东西,其实一直都很想用博客记录下自己学的点点滴滴,这样也能提高自己,今天终于是第一次尝试用博客,希望写的或者理解不到位的地方,请阅读的人多多指教!
首先来开始我们的正文,我们都知道造成时间冲突的原因是在布局中父控件和子控件谁去响应事件的问题
在viewgroup中,它包含三个方法分别是:
dispatchTouchEvent();
关于这个方法的作用,我查了一些资料
// 如果事件分发返回 false,表明事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费。 //如果事件分发返回true,表示改事件在本层不再进行分发且已经在事件分发自身中被消费了。至此,事件已经完结。 //如果事件分发返回系统默认的 super.dispatchTouchEvent(ev),事件将分发给本层的事件拦截onInterceptTouchEvent 方法进行处理
这个方法如果我们重写不管是你返回true还是false,本层的控件都不会去处理事件也不会向下传递,所以我们一般不要重写此方法,直接返回系统默认的比较好
onInterceptTouchEvent(MotionEvent ev)
//返回true表示拦截自己来处理,事件不向下传递,返回false表示不拦截事件向下传递
(只有viewgroup才有这个方法,view没有)
onTouch()方法返回true表示自己消费,返回false表示自己不消费,又会传递回去
其实事件的传递顺序是由外向内传递,如果最里面的不消费,又会由内向外传递回去,当然这个前提是事件没有被拦截
下面是我学习写的一个小demo,希望对你理解事件传递有帮助
我在一个线性布局中放置一个textview,给线性布局和textview都设置
onTouch 事件监听
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/rl" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff0000" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.administrator.shijianfenfa.MainActivity"> <LinearLayout android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="200dp" android:layout_centerInParent="true" android:background="#0000ff" android:gravity="center" android:text="我是textview" /> </LinearLayout>
然后给tv和ll设置事件
ll.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { int action = motionEvent.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e("cy", "ll " + "MotionEvent.ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e("cy", "ll " + "MotionEvent.ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e("cy", "ll " + "MotionEvent.ACTION_UP"); break; } return false; } }); tv.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { int action = motionEvent.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e("cy", "tv " + "MotionEvent.ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e("cy", "tv " + "MotionEvent.ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e("cy", "tv " + "MotionEvent.ACTION_UP"); break; } return false; } });
当手指点击textview时打印如下日志
tv MotionEvent.ACTION_DOWN
ll MotionEvent.ACTION_DOWN
当把textview的返回的改为true时
-24 17:48:36.893 14048-14048/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_DOWN
07-24 17:48:37.953 14048-14048/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_DOWN
07-24 17:48:37.983 14048-14048/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_MOVE
07-24 17:48:37.990 14048-14048/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_UP
改为true后textvie就能把这个事件捕获,所以把这个日志都打印出来
如果把tv改为false,ll改为true,那么这个事件就会被ll处理请看日志
07-24 17:52:38.265 16549-16549/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_DOWN
07-24 17:52:38.265 16549-16549/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_DOWN
07-24 17:52:38.291 16549-16549/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_MOVE
07-24 17:52:38.308 16549-16549/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_MOVE
07-24 17:52:38.324 16549-16549/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_MOVE
07-24 17:52:38.325 16549-16549/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_UP
从这个小例子我们可以明白,只有touch事件返回true表示自己处理此事件返回false则表示自己不处理(这个实在没有其它事件干扰的情况下)
现在我们把线性布局重写下,
public class MyLinearLayout extends LinearLayout { public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return false;//返回true表示拦截,事件不向下传递,返回false表示不拦截事件向下传递 } }
用这个线性布局替换掉系统的线性布局再试试
<com.example.administrator.shijianfenfa.MyLinearLayout android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="200dp" android:layout_centerInParent="true" android:background="#0000ff" android:gravity="center" android:text="我是textview" /> </com.example.administrator.shijianfenfa.MyLinearLayout>
设置他们的touch事件都返回true试试
07-24 17:58:22.773 16549-16549/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_DOWN
07-24 17:58:22.788 16549-16549/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_MOVE
07-24 17:58:22.805 16549-16549/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_MOVE
07-24 17:58:22.822 16549-16549/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_MOVE
07-24 17:58:22.835 16549-16549/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_MOVE
07-24 17:58:22.836 16549-16549/com.example.administrator.shijianfenfa E/cy: tv MotionEvent.ACTION_UP
事件就被textview处理啦
如果我们把自定义闲性布局中的改改
public class MyLinearLayout extends LinearLayout { public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true;//返回true表示拦截,事件不向下传递,返回false表示不拦截事件向下传递 }
07-24 18:01:27.936 21869-21869/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_DOWN 07-24 18:01:27.953 21869-21869/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_MOVE 07-24 18:01:27.970 21869-21869/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_MOVE 07-24 18:01:27.985 21869-21869/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_MOVE 07-24 18:01:27.986 21869-21869/com.example.administrator.shijianfenfa E/cy: ll MotionEvent.ACTION_UP }
其他的不变,预测tv应该不会检测到事件,因为被拦截,日志如上.
第一次写博客,思路也很凌乱,不知道怎么去表达和表现,希望不要拍砖!多多谅解!
事件传递是由上向下,一层一层传递,如果中途被拦截,就不会向下传递,如果此时这层的ontouch事件返回的是true,表示自己处理,如果不是则返回上一级,又一层层往上传!