Android之简述事件分发机制

基本手势事件

一、事件分发

顺序:Activity->ViewGroup->View

基本的手势事件主要有如下三个方法:

1、dispatchTouchEvent 

/**

    * 事件的分发

    * 分发事件的方法。当接收到事件时,通过调用此方法来决定是否分发。

    * @param ev

    * @return

    *  true: 事件不再进行分发且已经在自身事件的分发中被消费

    *  false: 也不对事件进行分发。

    *  也就是说该方法不论是返回true还是返回false都不会对事件进行分发,

    *  只有当返回系统默认super.dispatchTouchEvent(ev)时,才会将事件分发给本层 的拦截事件onInterceptTouchEvent(MotionEvent ev)去处理,

     *  如果没有onInterceptTouchEvent(MotionEvent ev)方法,则直接分发给子View中的onInterceptTouchEvent(MotionEvent ev)方法处理

    *

    */

    @Override

    public boolean dispatchTouchEvent(MotionEvent ev) {

        if(ev.getAction() == MotionEvent.ACTION_DOWN){

            Log.d("data","[LinearLayout]--dispatchTouchEvent:"+ev.getAction()+"    "+super.dispatchTouchEvent(ev));

        }

        return super.dispatchTouchEvent(ev);

    }

/*log日志

    *EventActivity: dispatchTouchEvent=====ACTION_DOWN

    *EventActivity: dispatchTouchEvent=====ACTION_UP

    */

注:View和ViewGroup在dispatchTouchEvent上的区别:

        ViewGroup在dispatchTouchEvent()中会进行事件的分发。

        View在dispatchTouchEvent()中会对该事件进行处理。

2、onInterceptTouchEvent

/**

    * 事件的拦截

    * 该方法只有在ViewGroup中才会有。通过调用该方法来决定是否对事件进行拦截。

    *  在dispatchTouchEvent的内部调用,用于判断是否拦截某个事件

    * @return

    *  true:进行拦截,将事件进行分发onTouchEvent方法处理

    *  false:不对事件进行拦截,传递给下一级处理

    */

    @Override

    public boolean onInterceptTouchEvent(MotionEvent ev) {

        if(ev.getAction() ==MotionEvent.ACTION_DOWN){

            Log.d("data","[LinearLayout]--onInterceptTouchEvent:"+ev.getAction()+"    "+super.onInterceptTouchEvent(ev));

        }

        return super.onInterceptTouchEvent(ev);

    }

3、onTouchEvent

/**

    * 事件的处理

    * 处理事件。当对事件进行了拦截时,将会调用onTouchEvent方法对事件进行处理。

    * 在dispatchTouchEvent中调用,用于处理点击事件

    * @param ev

    * @return

    *  true: 表示该View能处理该事件,事件将终止向上传递(传递给其父View)

    *  false: 不能处理,则把事件传递给其父View的onTouchEvent方法来处理

    */

    @Override

    public boolean onTouchEvent(MotionEvent ev) {

        if(ev.getAction() ==MotionEvent.ACTION_DOWN){

            Log.d("data","[LinearLayout]--onTouchEvent:"+ev.getAction()+"    "+super.onTouchEvent(ev));

        }

        return super.onTouchEvent(ev);

    }

    //注意:onTouchEvent事件消费函数一旦返回false 后面的鼠标UP 和 MOVE 就不会在这里执行了,但是下一次down事件能获取到

二、滑动冲突

场景:

1、内层和外层滑动方向不一致:一个垂直,一个水平。比如轮播图ViewPager和ScrollView;

2、内存和外层滑动方向一致:均垂直or水平。比如scrollView和RecyclerView;

3、前两者层层嵌套。比如ScrollView和RecyclerView(recyclerView中又嵌套recyclerView)

处理原则:

1、对于内外层滑动方向不同,只需要根据滑动方向来给相应控件拦截

2、对于内外层滑动方向相同,需要根据业务来进行事件拦截,规定何时让外部View拦截事件何时由内部View拦截事件。

3、前两者嵌套的情况,根据前两种原则层层处理即可。

解决办法:

内部拦截法:指父容器不拦截任何事件,而将所有的事件都传递给子容器,如果子容器需要此事件就直接消耗,否则就交由父容器进行处理。具体方法:需要配合requestDisallowInterceptTouchEvent方法。

外部拦截法:指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。

具体方法:需要重写父容器的onInterceptTouchEvent方法,在内部做出相应的拦截。

外部拦截要点:

父容器的onInterceptTouchEvent方法中处理

ACTION_DOWN不拦截,一旦拦截会导致后续事件都直接交给父容器处理。

ACTION_MOVE中根据情况进行拦截,拦截:return true,不拦截:return false(外部拦截核心)

ACTION_UP不拦截,如果父控件拦截UP,会导致子元素接收不到UP进一步会让onClick方法无法触发。此外UP拦截也没什么用。

你可能感兴趣的:(Android之简述事件分发机制)