当多个view重叠的时候事件是怎么处理的,又是怎么传递的,以前是一头雾水,今天通过列子进行了分析。
准备
首先准备如图的布局。其中GROUPA
为GROUPB
、VIEWC
的父类,GROUPB
为VIEWC
的父类
模拟角色:
经理->最外层ViewGroupA
组长->中间层ViewGroupB
你->最底层的码农ViewC
模拟:
经理分派任务,下属处理这个任务的过程。
先来看看代码
ViewGroup级别比较高,比View多一个onInterceptTouchEvent(拦截)。
ViewGroupA
public class ViewGroupA extends RelativeLayout{
public ViewGroupA(Context context) {
super(context);
}
public ViewGroupA(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupA(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("joker","GroupA-DispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("joker","GroupA-onTouchEvent");
return super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i("joker","GroupA-onInterceptTouchEvent");
return true;
}
}
ViewGroupB
public class ViewGroupB extends RelativeLayout {
public ViewGroupB(Context context) {
super(context);
}
public ViewGroupB(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupB(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("joker", "GroupB-DispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("joker", "GroupB-onTouchEvent");
return super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i("joker", "GroupB-onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
}
ViewC
public class ViewC extends View {
public ViewC(Context context) {
super(context);
}
public ViewC(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewC(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("joker", "ViewC-DispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("joker", "ViewC-onTouchEvent");
return super.onTouchEvent(event);
}
}
分析
情景1:
不做任何修改直接点击ViewC
Log信息如下
I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: ViewC-DispatchTouchEvent
I/joker: ViewC-onTouchEvent
I/joker: GroupB-onTouchEvent
I/joker: GroupA-onTouchEvent
Log信息看出,正常情况,事件传递顺序:
经理 –> 组长 –> 你,先执行dispatchTouchEvent(分发),再执行onInterceptTouchEvent(拦截)
事件处理顺序:
你 –> 组长 –> 经理,事件处理都是执行onTouchEvent(处理)。
事件传递返回值:true,拦截,交给自己的onTouchEvent处理;false,不拦截,传给下属。
事件处理返回值:true,自己搞定,不用上报上司;false,上报上司处理。
初始返回都是false。
事件传递,dispatchTouchEvent一般不太会改写,只关心onInterceptTouchEvent。
情景2:
经理觉得太简单自己处理
既ViewGroupA
里onInterceptTouchEvent
返回true,我们看下Log信息:
I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupA-onTouchEvent
经理把事情做完不会在交给下面的人处理。
情景3:
经理交给组长,组长觉得太简单自己处理
既ViewGroupB
里onInterceptTouchEvent
返回true,我们看下Log信息:
I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: GroupB-onTouchEvent
I/joker: GroupA-onTouchEvent
组长把事情做完不会再交给下面的人处理。
情景4
组长觉得你做的太烂了,不敢给经理上报
即ViewGroupB
里onTouchEvent
返回true,我们看下Log信息:
I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: ViewC-DispatchTouchEvent
I/joker: ViewC-onTouchEvent
I/joker: GroupB-onTouchEvent
事件处理经过你和组长,到组长那里就结束了。
情景5:
你迫于压力,辞职不干了,任务闲置
即ViewC
里onTouchEvent
返回true,我们看下Log信息:
I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: ViewC-DispatchTouchEvent
I/joker: ViewC-onTouchEvent
由于你辞职了,任务就被闲置到你这里就结束了而不会上报给上级了。
到此已经分析完整个过程不会在那样一头雾水。
再分析
给三个view添加ontouch事件
public class MainActivity extends AppCompatActivity {
private ViewGroupA a;
private ViewGroupB b;
private ViewC c;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
a = (ViewGroupA) findViewById(R.id.groupa);
b = (ViewGroupB) findViewById(R.id.groupb);
c = (ViewC) findViewById(R.id.viewc);
a.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i("joker", "A被点击了");
return false;
}
});
b.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i("joker", "B被点击了");
return false;
}
});
c.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i("joker", "C被点击了");
return false;
}
});
}
}
在不修改的情况下默认会打印什么?
让我们看Log:
I/joker: C被点击了
I/joker: B被点击了
I/joker: A被点击了
由此证实了onTouch是从下到上。
我们只想让C的信息打印又怎么修改呢?
相信大家已经有了很清晰的思路了只需要ViewC
的onTouch事件返回true;
那让C的信息不显示呢?
那就需要B进行拦截。只需要把ViewGroupB
的onInterceptTouchEvent事件返回true;
到此已经明白了事件分发传递的机制。
感谢《Android群英传》和小小龙博客