美文网首页
附:事件分发与传递

附:事件分发与传递

作者: 努力生活的西鱼 | 来源:发表于2019-02-26 17:12 被阅读0次

ViewGroup事件的传递和消耗

ViewGroup事件的消耗和传递主要由下面三个方法实现

dispatchTouchEvent(MotionEvent ev)
用于事件的分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。返回false则继续往下分发,如果是ViewGroup则分发给子View。

onInterceptTouchEvent()
ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在AndroidView是不能再包含子View的。

onTouchEvent(MotionEvent event)
用于事件的处理,返回true表示消费当前事件,返回false则不处理,交给子控件继续分发。

事件传递分析

事件分发

其中红色为ViewGroupA,绿色为ViewGroupB,蓝色为MyView

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) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d(getClass().getSimpleName(),"dispatchTouchEvent:ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d(getClass().getSimpleName(),"dispatchTouchEvent:ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.d(getClass().getSimpleName(),"dispatchTouchEvent:ACTION_UP");
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_UP");
                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d(getClass().getSimpleName(),"onTouchEvent:ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d(getClass().getSimpleName(),"onTouchEvent:ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.d(getClass().getSimpleName(),"onTouchEvent:ACTION_UP");
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }
}
1. 全部super父类的方法
打印日志:
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN
D/ViewGroupB: onTouchEvent:ACTION_DOWN
D/ViewGroupA: onTouchEvent:ACTION_DOWN
D/MainActivity: onTouchEvent:ACTION_DOWN
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/MainActivity: onTouchEvent:ACTION_UP

可以发现事件传递的方向是由外向内,如果都不消耗此事件,最后MainActivity会消耗掉。

2. MyView消耗掉事件

将MyView添加一个属性android:clickable="true"

----------------ACTION_DOWN-------------------
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN

----------------ACTION_MOVE-------------------
D/MainActivity: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: onInterceptTouchEvent:ACTION_MOVE
D/ViewGroupB: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupB: onInterceptTouchEvent:ACTION_MOVE
D/MyView: dispatchTouchEvent:ACTION_MOVE
D/MyView: onTouchEvent:ACTION_MOVE

----------------ACTION_UP-------------------
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: onInterceptTouchEvent:ACTION_UP
D/ViewGroupB: dispatchTouchEvent:ACTION_UP
D/ViewGroupB: onInterceptTouchEvent:ACTION_UP
D/MyView: dispatchTouchEvent:ACTION_UP
D/MyView: onTouchEvent:ACTION_UP
3. ViewGroupB拦截MOVE和UP事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_DOWN");
            return false;
        case MotionEvent.ACTION_MOVE:
            Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_MOVE");
            return true;
        case MotionEvent.ACTION_UP:
            Log.d(getClass().getSimpleName(),"onInterceptTouchEvent:ACTION_UP");
            return true;
        default:
            break;
    }
    return false;
}

打印日志

----------Action_Down----------
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN

----------Action_Move----------
D/MainActivity: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: onInterceptTouchEvent:ACTION_MOVE
D/ViewGroupB: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupB: onInterceptTouchEvent:ACTION_MOVE

----------Action_Up----------
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: onInterceptTouchEvent:ACTION_UP
D/ViewGroupB: dispatchTouchEvent:ACTION_UP
D/ViewGroupB: onTouchEvent:ACTION_UP
D/MainActivity: onTouchEvent:ACTION_UP

可以看到Action_Move和Action_Up只传递到ViewGroupB。

4. 在MyView中使用getParent().requestDisallowInterceptTouchEvent(true)
@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            getParent().requestDisallowInterceptTouchEvent(true);
            Log.d(getClass().getSimpleName(), "onTouchEvent:ACTION_DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d(getClass().getSimpleName(), "onTouchEvent:ACTION_MOVE");
            break;
        case MotionEvent.ACTION_UP:
            Log.d(getClass().getSimpleName(), "onTouchEvent:ACTION_UP");
            break;
        default:
            break;
    }
    return super.onTouchEvent(event);
}

打印日志

----------Action_Down----------
D/MainActivity: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupA: onInterceptTouchEvent:ACTION_DOWN
D/ViewGroupB: dispatchTouchEvent:ACTION_DOWN
D/ViewGroupB: onInterceptTouchEvent:ACTION_DOWN
D/MyView: dispatchTouchEvent:ACTION_DOWN
D/MyView: onTouchEvent:ACTION_DOWN

----------Action_Move----------
D/MainActivity: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupA: dispatchTouchEvent:ACTION_MOVE
D/ViewGroupB: dispatchTouchEvent:ACTION_MOVE
D/MyView: dispatchTouchEvent:ACTION_MOVE
D/MyView: onTouchEvent:ACTION_MOVE

----------Action_Up----------
D/MainActivity: dispatchTouchEvent:ACTION_UP
D/ViewGroupA: dispatchTouchEvent:ACTION_UP
D/ViewGroupB: dispatchTouchEvent:ACTION_UP
D/MyView: dispatchTouchEvent:ACTION_UP
D/MyView: onTouchEvent:ACTION_UP

可以发现MOVE和UP事件又可以传递到MyView中了。

可以参考:
https://juejin.im/post/5cbfaf476fb9a032363933ac

相关文章

网友评论

      本文标题:附:事件分发与传递

      本文链接:https://www.haomeiwen.com/subject/ulczyqtx.html