View以及ViewGroup的事件处理流程

关于View的事件分发,这篇博客 讲的很清楚,大致总结下事件的流程

View.dispatchEvent->View.setOnTouchListener->View.onTouchEvent

在dispatchTouchEvent中会进行OnTouchListener的判断,如果这个view处于enable状态,OnTouchListener不为null且返回true,则表示事件被消费,onTouchEvent不会被执行;否则执行onTouchEvent。

在onTouchEvent中,如果return true就说明事件被消费了,当然如果这个View可以被点击(可以在代码中设置view.setonClickListener),或者长按(可以设置view.setonLongClickListener),也可以说明事件被消费


而他的后续博客也对ViewGroup的源码分析的很清楚,但是看了源码还是自己动手验证下嘛,因为我就写一写ViewGroup的事件的demo

    
    
    
    
package com.example.user.swipeview_01;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/**
* Created by USER on 2015/9/30.
*/
public class MyLinearLayout extends LinearLayout {
private static final String TAG = "zhou";
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d(TAG,"MyLinearLayout -> dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d(TAG,"MyLinearLayout -> onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"MyLinearLayout -> onTouchEvent->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"MyLinearLayout -> onTouchEvent->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG,"MyLinearLayout -> onTouchEvent->ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}
     
     
     
     
package com.example.user.swipeview_01;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by USER on 2015/9/30.
*/
public class MyView extends View {
private static final String TAG ="zhou";
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d(TAG,"MyView->dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"MyView->onTouchEvent->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"MyView->onTouchEvent->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG,"MyView->onTouchEvent->ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}

布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.user.swipeview_01.MyLinearLayout
        android:background="#eeee5046"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.example.user.swipeview_01.MyView
            android:background="#ee93ee74"
            android:layout_width="300dp"
            android:layout_height="200dp" />
    </com.example.user.swipeview_01.MyLinearLayout>

</LinearLayout>


如果都不做事件的拦截的话
    
    
    
    
09-30 18:12:03.485 14514-14514/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
09-30 18:12:03.485 14514-14514/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
09-30 18:12:03.486 14514-14514/com.example.user.swipeview_01 D/zhou﹕ MyView->dispatchTouchEvent
09-30 18:12:03.489 14514-14514/com.example.user.swipeview_01 D/zhou﹕ MyView->onTouchEvent->ACTION_DOWN
09-30 18:12:03.493 14514-14514/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_DOWN
ViewGroup(dispatchTouchEvent) -> ViewGroup(onInterceptTouchEvent)->Vie事件流程->ViewGroup(onTouchEvent)
为什么没有ACTION_MOVE 和 ACTION_UP事件,因为在ACTION_DOWN的时候,MyView不要,MyLinearLayout不要,事件就没有被消费,就没有找到target,所以后面就不用处理了


如果在MyView的onTouchEvent的最后返回的值为true的话
    
    
    
    
09-30 18:18:30.736 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
09-30 18:18:30.736 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
09-30 18:18:30.737 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->dispatchTouchEvent
09-30 18:18:30.741 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->onTouchEvent->ACTION_DOWN
09-30 18:18:30.764 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
09-30 18:18:30.764 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
09-30 18:18:30.765 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->dispatchTouchEvent
09-30 18:18:30.765 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->onTouchEvent->ACTION_MOVE
09-30 18:18:30.784 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
09-30 18:18:30.784 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
09-30 18:18:30.784 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->dispatchTouchEvent
09-30 18:18:30.785 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->onTouchEvent->ACTION_MOVE
09-30 18:18:30.793 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
09-30 18:18:30.793 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
09-30 18:18:30.793 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->dispatchTouchEvent
09-30 18:18:30.796 16701-16701/com.example.user.swipeview_01 D/zhou﹕ MyView->onTouchEvent->ACTION_UP
可以看到在MyView的onTouchEvent的ACTION_DOWN中消费了事件,MyLinearLayout的onTouchEvent就不能处理ACTION_DOWN了,既然找到了target为MyView,那么事件每次都要继续往下传递,然后的ACTION_MOVE和ACTION_UP都会最终到MyView处理了,不再到MyLinearLayout中的onTouchEvent了

如果在MyView的onTouchEvent返回true,再把MyLinearLayout中的onIntercetptTouchEvent返回true ,也就是说MyLinearLayout要截断这个事件不让事件往下传到MyView
    
    
    
    
10-08 09:52:19.038 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:52:19.039 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
10-08 09:52:19.041 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_DOWN
10-08 09:52:20.009 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:52:20.009 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
10-08 09:52:20.011 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_DOWN
10-08 09:52:20.698 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:52:20.699 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
10-08 09:52:20.702 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_DOWN
10-08 09:52:21.544 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:52:21.544 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
10-08 09:52:21.546 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_DOWN
10-08 09:54:51.304 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:54:51.305 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
10-08 09:54:51.307 5891-5891/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_DOWN
我们可以看到,事件已经不在传递到MyView,只会传递到MyLinearLayout的onTouchEvent中,但是也只是处理ACTION_DOWN,这又是怎么回事呢,因为在MyLinearLayout中的onTouchEvent,我们没有对事件进行消费,也就是说没有return true,而是把事件交给了父View处理,也就是super.onTouchEvent。

既然这样,我们再把MyLinearlayout中的onTouchEvent返回true试试 
    
    
    
    
10-08 09:58:18.037 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.037 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onInterceptTouchEvent
10-08 09:58:18.040 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_DOWN
10-08 09:58:18.054 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.056 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.071 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.071 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.091 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.091 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.108 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.109 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.127 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.127 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.147 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.148 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.164 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.165 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.184 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.184 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.195 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.195 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 09:58:18.204 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> dispatchTouchEvent
10-08 09:58:18.207 7250-7250/com.example.user.swipeview_01 D/zhou﹕ MyLinearLayout -> onTouchEvent->ACTION_UP

OK,如我们之前所说,既然onInterceptTouchEvent方法,截断了事件往下传递,那么自己就应该处理事件,在ACTION_DOWN事件中,正好我们现在在MyLinearLayout中的onTouchEvent方法中返回了true(自己处理),所以就找到了target来处理后面的事件,上面 的Log信息正是这样。


现在总结 下,关键在哪里呢,target!  也就是ACTION_DOWN事件找的target,如果在ACTION_DOWN的时候没有找到target,那么 走系统的流程,如果找到了后续所有事件都由这个target处理。 好,我们来验证我们的结论

在MyLinearLayout中
    
    
    
    
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d(TAG,"MyLinearLayout -> onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
 
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"MyLinearLayout -> onTouchEvent->ACTION_DOWN");
return true;
 
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"MyLinearLayout -> onTouchEvent->ACTION_MOVE");
break;
 
case MotionEvent.ACTION_UP:
Log.d(TAG,"MyLinearLayout -> onTouchEvent->ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
没有截断事件,只在ACTION_DOWN事件中返回true,也就是说如果target为MyLinearLayout,后续事件都由MyLinearLayout来处理

在MyView中
    
    
    
    
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"MyView->onTouchEvent->ACTION_DOWN");
return super.onTouchEvent(event);
//break;
 
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"MyView->onTouchEvent->ACTION_MOVE");
break;
 
case MotionEvent.ACTION_UP:
Log.d(TAG,"MyView->onTouchEvent->ACTION_UP");
break;
 
}
//return super.onTouchEvent(event);
return true;
}
我们在ACTION_DOWN事件中,没有返回true,在其它事件中返回了true,也就是说我们不让target为MyView,所以后续就算ACTION_MOVE , ACTION_UP返回true,也不会到这里处理

看下Log信息
    
    
    
    
10-08 10:06:23.156 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> dispatchTouchEvent
10-08 10:06:23.157 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> onInterceptTouchEvent
10-08 10:06:23.157 9343-9343/com.example.user.swipeview_01 D/zhou MyView->dispatchTouchEvent
10-08 10:06:23.162 9343-9343/com.example.user.swipeview_01 D/zhou MyView->onTouchEvent->ACTION_DOWN
10-08 10:06:23.164 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> onTouchEvent->ACTION_DOWN
10-08 10:06:23.178 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> dispatchTouchEvent
10-08 10:06:23.179 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 10:06:23.199 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> dispatchTouchEvent
10-08 10:06:23.200 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 10:06:23.218 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> dispatchTouchEvent
10-08 10:06:23.218 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 10:06:23.229 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> dispatchTouchEvent
10-08 10:06:23.229 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> onTouchEvent->ACTION_MOVE
10-08 10:06:23.236 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> dispatchTouchEvent
10-08 10:06:23.239 9343-9343/com.example.user.swipeview_01 D/zhou MyLinearLayout -> onTouchEvent->ACTION_UP
很好,正如我们所料,在ACTION_DOWN时候走了系统的流程,dispatchTouchEvent( MyLinearLayout   ) -> onInterceptTouchEvent(MyLinearLayout ) -> dispatchTouchEvent(MyView ) -> onTouchEvent(MyView):ACTION_DOWN
但是MyView的onTouchEvent并没有返回true,自然转到了MyLinearLayout中的onTouchEvent了,而此时ACTION_DOWN返回了true,也就是说MyLinearLayout作为 了这个事件的target,就算MyLinearLayout的ACTION_MOVE,ACTION_UP走的是系统流程,照样进行事件处理,为什么,因为劳资就是target,不给我处理,给谁处理~ 

画个草图看下事件如何找到target的,只要target找到以后都由这个target来处理事件,除非有特殊情况 ,例如子View,getParent().requestDisallowInterceptTouchEvent(true)不允许父View截断事件,当然这是后话


View以及ViewGroup的事件处理流程_第1张图片

当我们找到target以后 ,其它的View的onTouchEvent必然不会再处理事件了,后续我会用一些demo来验证这些理论。

读源码有时候并不容易 ,但是既然有人已经 做过这些事情,我就不做了,因为我不需要去写源码 ,我只需要知道这个东西如何用就行,当然如果你够强大 ,就从源码学习吧~












你可能感兴趣的:(View以及ViewGroup的事件处理流程)