Andriod高级开发工程师-事件分发机制

529 阅读4分钟

事件分发主要方法

  • dispatchTouchEvent(MotionEvent event) 事件分发方法。
  • onInterceptTouchEvent(MotionEvent event) 事件拦截方法,只在ViewGroup中。
  • onTouchEvent(MotionEvent event) 事件处理方法。

通过Demo来分析

public class DispatchActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Util.printLog("Activity dispatchTouchEvent", event);
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("Activity onTouchEvent", event);
        return super.onTouchEvent(event);
    }
}

ViewGroup dispatchTouchEvent返回true

public class EventViewGroup extends LinearLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup dispatchTouchEvent", event);
        return true;
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onInterceptTouchEvent", event);
        return super.onInterceptTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onTouchEvent", event);
        return super.onTouchEvent(event);
    }
}
// 输出日志
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP

可见,如果ViewGroup dispatchTouchEvent返回true,则不会执行子View的任何方法,也不会执行ViewGroup的onTouch方法。

ViewGroup dispatchTouchEvent返回true,且onTouch返回true

public class EventViewGroup extends LinearLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup dispatchTouchEvent", event);
        return true;
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onInterceptTouchEvent", event);
        return super.onInterceptTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onTouchEvent", event);
        return true;
    }
}
// 输出日志
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP

可见,如果ViewGroup dispatchTouchEvent返回true,无论onTouchEvent是否返回true,则不会执行子View的任何方法,也不会执行ViewGroup的onTouch方法。

ViewGroup onInterceptTouchEvent返回true

public class EventViewGroup extends LinearLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup dispatchTouchEvent", event);
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onInterceptTouchEvent", event);
        return true;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onTouchEvent", event);
        return super.onTouchEvent(event);
    }
}
// 输入日志
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
ViewGroup onTouchEvent ACTION_DOWN

Activity onTouchEvent ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
Activity onTouchEvent ACTION_MOVE
......
Activity dispatchTouchEvent ACTION_MOVE
Activity onTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
Activity onTouchEvent ACTION_UP

可见,如果ViewGroup onInterceptTouchEvent返回true,而onTouchEvent返回false,则不会执行子View的任何方法,只会执行一次ViewGroup的onTouchEvent,因为没有返回true,即不处理,则会返回上层Activity执行其onTouchEvent。以后也不会再执行ViewGroup的任何方法。

ViewGroup onInterceptTouchEvent返回true,onTouchEvent返回true

public class EventViewGroup extends LinearLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup dispatchTouchEvent", event);
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onInterceptTouchEvent", event);
        return true;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("ViewGroup onTouchEvent", event);
        return true;
    }
}
// 输出日志
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
ViewGroup onTouchEvent ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
ViewGroup onTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP
ViewGroup onTouchEvent ACTION_UP

可见,如果ViewGroup onInterceptTouchEvent返回true,且onTouchEvent返回true,则不会执行子View的任何方法,而是后续都会执行ViewGroup的onTouchEvent,即由ViewGroup的onTouchEvent来处理后续的事件,且同时也会执行Activity和ViewGroup的dispatchTouchEvent。

View的dispatchTouchEvent返回true

public class EventView extends TextView {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return true;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("View onTouchEvent", event);
        return super.onTouchEvent(event);
    }
}
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
View dispatchTouchEvent ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
ViewGroup onInterceptTouchEvent ACTION_MOVE
View dispatchTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
ViewGroup onInterceptTouchEvent ACTION_MOVE
View dispatchTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP
ViewGroup onInterceptTouchEvent ACTION_UP
View dispatchTouchEvent ACTION_UP

可见,如果View dispatchTouchEvent返回true,而onTouchEvent返回false,则不会执行View的onTouchEvent,而只会执行View的dispatchTouchEvent。

View的dispatchTouchEvent返回false,而onTouch返回false

public class EventView extends TextView {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Util.printLog("View dispatchTouchEvent", event);
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("View onTouchEvent", event);
        return super.onTouchEvent(event);
    }
}
// 输入日志
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
View dispatchTouchEvent ACTION_DOWN
View onTouchEvent ACTION_DOWN
ViewGroup onTouchEvent ACTION_DOWN
Activity onTouchEvent ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
Activity onTouchEvent ACTION_MOVE
......
Activity dispatchTouchEvent ACTION_MOVE
Activity onTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
Activity onTouchEvent ACTION_UP

可见,如果View dispatchTouchEvent返回false,onTouchEvent返回false,只会执行一次View的onTouchEvent,因为没有返回true,即不处理后续的事件,则会返回上层ViewGroup或Activity执行其onTouchEvent。以后也不会再执行View的任何方法。

View的dispatchTouchEvent返回false,而onTouch返回true

public class EventView extends TextView {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Util.printLog("View dispatchTouchEvent", event);
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("View onTouchEvent", event);
        return true;
    }
}
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
View dispatchTouchEvent ACTION_DOWN
View onTouchEvent ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
ViewGroup onInterceptTouchEvent ACTION_MOVE
View dispatchTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP
ViewGroup onInterceptTouchEvent ACTION_UP
View dispatchTouchEvent ACTION_UP
View onTouchEvent ACTION_UP

可见,View dispatchTouchEvent返回false,onTouchEvent返回true,说明View来处理后续事件,即会执行View的onTouch,不会再调用ViewGroup或Activity。

事件序列如下

事件分发模型如下

结论

即onTouch中在哪消费的Down事件,则后续的MOVE、UP等事件,只会传递到该View,而不会再分发给其子View,所以也不会执行子View的dispatchTouchEvent。

最后介绍下setOnToucheListener、setOnClickListener执行时机

setOnToucheListener

public class EventView extends TextView implements View.OnTouchListener, View.OnClickListener {
    private void init() {
        setOnTouchListener(this);
        setOnClickListener(this);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("View onTouchEvent", event);
        return true;
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Util.printLog("View OnTouchListener onTouch", event);
        return false;
    }
    @Override
    public void onClick(View v) {
        Util.printLog("View OnClickListener onClick", null);
    }
}
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
View dispatchTouchEvent ACTION_DOWN
View OnTouchListener onTouch ACTION_DOWN
View onTouchEvent ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
ViewGroup onInterceptTouchEvent ACTION_MOVE
View dispatchTouchEvent ACTION_MOVE
View OnTouchListener onTouch ACTION_MOVE
View onTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP
ViewGroup onInterceptTouchEvent ACTION_UP
View dispatchTouchEvent ACTION_UP
View OnTouchListener onTouch ACTION_UP
View onTouchEvent ACTION_UP

可见,View 会先执行onTouchListener中的onTouch,如果返回false,则会继续执行onTouchEvent,但不执行onClickListener,因为onTouchEvent返回true。

public class EventView extends TextView implements View.OnTouchListener, View.OnClickListener {
    private void init() {
        setOnTouchListener(this);
        setOnClickListener(this);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Util.printLog("View onTouchEvent", event);
        return super.onTouchEvent(event);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Util.printLog("View OnTouchListener onTouch", event);
        return true;
    }
    @Override
    public void onClick(View v) {
        Util.printLog("View OnClickListener onClick", null);
    }
}
Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
View dispatchTouchEvent ACTION_DOWN
View OnTouchListener onTouch ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
ViewGroup onInterceptTouchEvent ACTION_MOVE
View dispatchTouchEvent ACTION_MOVE
View OnTouchListener onTouch ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP
ViewGroup onInterceptTouchEvent ACTION_UP
View dispatchTouchEvent ACTION_UP
View OnTouchListener onTouch ACTION_UP

可见,View 会先执行onTouchListener中的onTouch,如果返回true,则不会继续执行onTouchEvent。

setOnToucheListener

只有onTouch和onTouchEvent都返回false,则会执行onClickListenr

Activity dispatchTouchEvent ACTION_DOWN
ViewGroup dispatchTouchEvent ACTION_DOWN
ViewGroup onInterceptTouchEvent ACTION_DOWN
View dispatchTouchEvent ACTION_DOWN
View OnTouchListener onTouch ACTION_DOWN
View onTouchEvent ACTION_DOWN

Activity dispatchTouchEvent ACTION_MOVE
ViewGroup dispatchTouchEvent ACTION_MOVE
ViewGroup onInterceptTouchEvent ACTION_MOVE
View dispatchTouchEvent ACTION_MOVE
View OnTouchListener onTouch ACTION_MOVE
View onTouchEvent ACTION_MOVE

Activity dispatchTouchEvent ACTION_UP
ViewGroup dispatchTouchEvent ACTION_UP
ViewGroup onInterceptTouchEvent ACTION_UP
View dispatchTouchEvent ACTION_UP
View OnTouchListener onTouch ACTION_UP
View onTouchEvent ACTION_UP

View OnClickListener onClick

注意,OnClickListenr.onClick是在执行完ACTION_UP后执行的

最后看下源码

Activity
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }
PhoneWindow
    @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }
DecorView 即 ViewGroup
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    }

源码我就不分析了,网上很多文章。