Android面试准备:事件分发机制

转自https://blog.csdn.net/a362523/article/details/48933439

View的事件分发机制举例

  1. 为按钮设置onClick点击事件和onTouch触摸事件的执行顺序为:
    1、onClick事件:
button.setOnClickListener(new OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Log.d("TAG", "onClick execute");  
    }  
});  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、onTouch事件:

button.setOnTouchListener(new OnTouchListener() {  
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
        Log.d("TAG", "onTouch execute, action " + event.getAction());  
        return false;  
    }  
});  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3、执行次序为:
onTouch是优先于onClick执行的,并且onTouch执行了两次,一次是按下ACTION_DOWN,一次是抬起ACTION_UP(你还可能会有多次移动ACTION_MOVE的执行,如果你手抖了一下)。因此事件传递的顺序是先经过onTouch,再传递到onClick。
4、onTouch方法是有返回值的,这里我们返回的是false,表示事件会继续传递;为true表示事件不继续传递了。(可以理解成事件被onTouch消费掉了)

  1. 只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法(该方法在View中)
    dispatchTouchEvent源码为:
public boolean dispatchTouchEvent(MotionEvent event) {  
    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
            mOnTouchListener.onTouch(this, event)) {  
        return true;  
    }  
    return onTouchEvent(event);  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1、如果条件为真,则执行onTouch(this, event)方法,否则执行的是onTouchEvent(event);
3、三个条件依次是:注册监听 + 控件处于enabled状态 + onTouch方法的返回值(也就是如果这个onTouch回调函数的返回值为true,则执行onTouch而不会执行 onTouchEvent(event),否则执行的是onTouchEvent(event),这就是为什么刚刚说“被消耗掉”了的原因)
3、onClick方法在onTouchEvent(event)方法中,当按钮状态为MotionEvent.ACTION_UP(即点击)时,会执行performClick()方法里回调被点击控件的onClick方方法

  1. 就是touch事件的层级传递。
    1、我们都知道如果给一个控件注册了touch事件,每次点击它的时候都会触发一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等事件。这里需要注意,如果你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action。
    2、touch事件分发的机制总结为:
    就拿按钮点击事件为例的touch事件分发的执行过程为:
    ①、当触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法
    ②、dispatchTouchEvent方法中首先会执行onTouch这个回调函数,但是执行onTouch这个回调函数有两个前提条件、第一个提前提条件是该控件注册了触摸监听,第二个条件是该控件是的状态是Enable的。
    ③、onTouch回调函数会有一个返回值,返回这如果为true的话就代表本次触摸事件被消耗掉了,执行接触;返回值为false的话会继续执行onTouchEvent方法。
    ④、onTouchEvent方法就是真正执行点击事件的地方,也就是我们重写的onClick方法。
    ⑤、onTouchEvent方法中能够捕获一次点击事件当中ACTION_DOWN、ACTION_ MOVE、ACTION_UP这三个中作,当触摸动作为ACTION_UP会调用onClick方法。

ViewGroup的事件分发机制

  1. ViewGroup的定义
    Android中任何控件都是直接或者间接集成View的,ViewGroup也是一样,ViewGroup可以简单理解成一组View的集合,它里面既可以包含View,也可以包含ViewGroup,譬如说我们熟悉的LinearLayout、RelativeLayout布局就是ViewGroup的子类。
  2. ViewGroup的事件分发举例
    1、MyLayout继承LinaerLayout + 两个Button + 设置监听
myLayout.setOnTouchListener(new OnTouchListener() {  
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
        Log.d("TAG", "myLayout on touch");  
        return false;  
    }  
});  
button1.setOnClickListener(new OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Log.d("TAG", "You clicked button1");  
    }  
});  
button2.setOnClickListener(new OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Log.d("TAG", "You clicked button2");  
    }  
});  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

2、分别点击的结果为:
这里写图片描述
即当点击按钮的时候,MyLayout注册的onTouch方法并不会执行,只有点击空白区域的时候才会执行该方法。
可以先理解成Button的onClick方法将事件消费掉了,因此事件不会再继续向下传递。
3、ViewGroup中有一个onInterceptTouchEvent方法

public boolean onInterceptTouchEvent(MotionEvent ev) {  
    return false;  
} 
  • 1
  • 2
  • 3

如果重写这个方法,返回true的话执行结果为:
这里写图片描述
3. ViewGroup事件分发的流程
1、Android中touch事件的传递,绝对是先传递到ViewGroup,再传递到View的
2、当你点击了某个控件,首先会去调用该控件所在ViewGroup的dispatchTouchEvent方法,然后在布局的dispatchTouchEvent方法中找到被点击的相应控件,再去调用该控件的dispatchTouchEvent方法。
3、其中会有一个onInterceptTouchEvent方法对事件传递进行拦截,如果返回值为true的话就表示事件不往子View中传递,如果为false的话就表示不对事件传递进行拦截,事件会往子View中传递

Android事件分发机制大总结

  1. Android中的控件都是直接或者间接继承View的,Viewgroup也是继承View的,ViewGroup中可以包含View,也可以包含ViewGroup,我们平时接触的譬如说LinearLayout啊、RelativeLayout就是ViewGroup的子类。
  2. Android的事件分发机制我有看过它的源码,总的来说就是Android中触摸事件的传递都是先传递到ViewGroup,再传递到View的。我就举Button点击这个例子来讲解一下Android中触摸事件分发的大致流程吧。
  3. 当点击Button的时候,会调用这个控件所在布局的dispatchTouchEvent(),然后在这个布局中dispatchTouchEvent()方法中找到被点击控件的dispatchTouchEvent()方法。
  4. 在调用被点击控件的dispatchTouchEvent()方法之前会有一次触摸事件的拦截判断,如果触摸事件被拦截了,就不会再去执行被点击控件的dispatchTouchEvent函数了,也就不会再执行onClick点击事件了。而是执行ViewGroup控件中的dispatchTouchEvent()的onTouch触摸事件然后返回。
  5. 如果触摸事件没被拦截的话又是怎么做呢,就会ViewGroup中dispatchTouchEvent()方法中被点击控件的dispatchTouchEvent()方法,就不会执行ViewGroup中的onTouch方法了。
  6. 以上只是阐述了touch事件在ViewGroup中和View中的事件分发过程,但是具体得在一个View中的touch事件分发机制又是怎么样的呢,我们继续往下看
  7. android里面当触摸到任何一个控件的时候就一定会调用这个控件的dispatchTouchEvent方法。dispatchTouchEvent方法中的源码首先会调用onTouch方法,不过这个方法要执行的话也需要有两个前提条件,一个是这个控件注册了触摸监听、第二个是这个控件的状态要是enabled的。
  8. 执行完onTouch方法之后,会有一个返回值,如果返回这为true的话代表这个点击事件不继续往下传递了,为false的话就表示点击事件继续往下传递,就会执行onTouchEvent方法,onClick方法就是在onTouchEvent中被调用的。
  9. 这样的话一个控件的触摸事件在ViewGroup以及View中的分发过程就完成了。

你可能感兴趣的:(android)