我在昨天的博客里面转载了一篇写的比较好的关于事件分发机制的文章,想要了解分发机制的相关信息的可以移步https://blog.csdn.net/WalterZhoukick/article/details/82628902
这篇文章只谈我看了昨天的文章之后,对事件分发机制的理解的用法
其实看过我之前的博客的朋友,对事件分发已经有了一个大概的概念。
事件分发,指的就是手指在屏幕上的一系列操作,包括
1.手指按下(down)
2.手指移动(move)
3.手指抬起(up)
每一个事件都以down开始,up结束。
而我们平时所说的事件分发,其实就是这一系列操作的运行顺序
我们如果按照三层顺序来说,分别是Activity,viewgroup,view
布局大概就是上图的样子,我们接下来讲具体的事件分发顺序
1.手指接触屏幕
这里个人感觉应该是手机屏幕感应到有按压,然后传回android系统分析,android系统传给我们现在所显示的activty中。从这里开始,我们经常所说的事件分发正式开始
首先是Activity
上面的这个,是activty的dispatchTouchEvent方法,我这里是重载了一遍
注意,我是在进入方法的时候打了一个Log,调用super之后打了一个Log
下面我们看super.dispatchTouchEvent方法
这个就是Activity的源码
我们可以看到它是return的 Activity的onTouchEvent
一样,我这里也是打了两个Log
我们看super.onTouchEvent
这里判断一下是不是在view上面,如果不在view上面就返回返回false,继续传递。否则停止传递
到这里为止,事件分发的第一步已经走完了
下面我们看viewgroup的事件分发
这里的dispatchTouchEvent方法和onTouchEvent方法的流程和Activity是一样的,不在做解释
要重点解释的是onInterceptTouchEvent这个方法
我把它叫拦截器,这里是拦截事件要不要继续往view层传递的方法
我们看源码
每次都会问一下这个拦截器要不要继续往下走
到了这里,差不多viewgroup的事件分发也就讲完了,下面看view的
和activity的差不多,也不再描述。
我们之前做了这么多解析,为的就是看这最后一步
我们先不改动任何方法,只看正常点击TestBtn的事件是怎么走的
上面的Log,是我手指按下去的时候打印出来的,这个时候我并没有移动和抬起手指
所以顺序是
1.进入activity的dispatchTouchEvent
2.事件传递进入viewgroup的dispatchTouchEvent
3.判断拦截器
4.拦截器返回数据,不拦截,进入view
5.进入view的dispatchTouchEvent
6.进入view的onTouchEvent
7.返回view的onTouchEvent
8.返回viewgroup的onTouchEvent
9.返回activity的dispatchTouchEvent
以上9步只是我手指按下的操作,抬起的流程也是一样:
我们看到最后才调用了view的onclick方法
到这里为止,一个正常的事件分发就已经完成了。
那我们为什么需要了解事件分发机制,又或者这个机制我们可以做什么改动?
其实无非就是三种情况:
a.要把点击事件控制在activity,不传递下去
b.要把点击事件控制在viewgroup,不传递下去
c.正常传递消费事件即可
解决方案也很简单
a.在activity的dispatchTouchEvent方法里面,不调用super即可
注意,这里不能写return false,因为所有的事件传递都在super里面
b.把拦截器return的值改为true
c.不做修改
具体的log我就不贴出来了,本人是亲自测试的,相应的文件代码也会贴出来给大家
/**
* Created by Walter on 2018/8/8.
*/
public class TestActivity extends AppCompatActivity {
private TestBtn btn;
private TestLayout layout;
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
btn = findViewById(R.id.test_btn);
layout = findViewById(R.id.test_layout);
layout.setOnClickListener(v -> {
LogUtils.e("Layout OnClick");
});
btn.setOnClickListener(v -> {
LogUtils.e("View OnClick");
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
LogUtils.e("Activity dispatchTouchEvent ");
boolean re = super.dispatchTouchEvent(ev);
LogUtils.e("Activity dispatchTouchEvent " + re);
return re;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
LogUtils.e("Activity onTouchEvent ");
boolean re = super.onTouchEvent(event);
LogUtils.e("Activity onTouchEvent " + re);
return re;
}
}
/**
* Created by Walter on 2018/9/11.
*/
public class TestLayout extends LinearLayout {
public TestLayout(Context context) {
super(context);
}
public TestLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public TestLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
LogUtils.e("TestLayout dispatchTouchEvent ");
boolean re = super.dispatchTouchEvent(ev);
LogUtils.e("TestLayout Layout dispatchTouchEvent " + re);
return re;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
LogUtils.e("TestLayout onTouchEvent ");
boolean re = super.onTouchEvent(event);
LogUtils.e("TestLayout Layout onTouchEvent " + re);
return re;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
LogUtils.e("TestLayout onInterceptTouchEvent ");
boolean re = super.onInterceptTouchEvent(ev);
LogUtils.e("TestLayout Layout onInterceptTouchEvent " + re);
return re;
}
}
/**
* Created by Walter on 2018/9/11.
*/
@SuppressLint("AppCompatCustomView")
public class TestBtn extends Button {
public TestBtn(Context context) {
super(context);
}
public TestBtn(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TestBtn(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
LogUtils.e("TestBtn dispatchTouchEvent ");
boolean re = super.dispatchTouchEvent(event);
LogUtils.e("TestBtn View dispatchTouchEvent " + re);
return re;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
LogUtils.e("TestBtn onTouchEvent ");
boolean re = super.onTouchEvent(event);
LogUtils.e("TestBtn View onTouchEvent " + re);
return re;
}
}
以上,均为原创