Android开发艺术探索读书笔记-View的事件体系(二)

来源:互联网 发布:苹果截图快捷键mac 编辑:程序博客网 时间:2024/05/16 19:42

1.View的事件分发机制相关方法

public boolean dipatchTouchEvent()
public boolean onInterceptTouchEvent()
public boolean onTouchEvent()

书中以伪代码的形式展示的这三个方法的关联性,我用我的这篇blog的Android源码又详细梳理了一下三个方法的关联性,数字为代码对应的行号(http://blog.csdn.net/langyw98/article/details/77808391)

//一个系列的事件是以ACTION_DOWN开始的//ACTION_DOWN事件派发从根布局的ViewGroup.java的dispatchTouchEvent()开始2077:dispatchTouchEvent()2108:onInterceptTouchEvent()2133:intercepted == false2197:dispatchTransformedTouchEvent()//派发给子View2240:intercepted == true2240:dispatchTransformedTouchEvent()//第3个参数为null,也就是把ViewGroup按View来处理//在dispatchTransFormedTouchEvent()中所有的事件派发都分成了child == null和child != null两类2565:child == null2566:super.dispatchTouchEvent(transformedEvent)2575:child != null2575:child.dispatchTouchEvent(transformedEvent)View.java的dispatchTouchEvent9262:dispatchTouchEvent()9228:onTouch()//回调先截获事件,如果不消费则由View的onTouchEvent处理9294:onTouchEvent

2.事件分发顺序:
Activity->Window->Decor view->子View分发
3.一个事件序列(从Action_down->Action_up)只能被一个View拦截且消耗。
4.onTouch(setOnTouchListener)比onTouchEvent先调用。
5.如果想处理所有的点击事件,要在dipatchTouchEvent中处理,因为onInterceptTouchEvent不是一定会被调用的。

disallowIntercept的作用
ViewGroup有一个disallowIntercept开关,可以设置此ViewGroup是否屏蔽onInterceptTouchEvent事件。如果开启此开关,则此ViewGroup跳过自身的onInterceptTouchEvent事件,直接dispatchTouchEvent到子View。
重置disallowIntercept
disallowIntercept,会在每次ACTION_DOWN被重置,默认为允许调用onInterceptTouchEvent。

ACTION_DOWN是一个特殊的事件

1.首先此事件发生时会将mFirstTouchTarget置为null
2098:cancelAndClearTouchTargets(ev)
2.在本次事件中,设置mFirstTouchTarget,也就是后续会处理系列事件的子View,可能为空,即子View都不想处理这个事件
2213:newTouchTarget = addTouchTarget(child, idBitsToAssign)
3.在这个事件中会判断当前ViewGroup是否要拦截事件
2108:onInterceptTouchEvent()

6.滑动冲突可以归结为“不同方向上的滑动冲突”和“同方向上的滑动冲突”。
7.父容器可滑动,在父容器中还存在一个子元素也可以滑动,解决滑动冲突的两种思路:
①外部拦截法,也就是在父容器当中进行滑动事件的拦截,在父容器的onInterceptTouchEvent方法中处理,ACTION_DOWN和ACTION_UP事件不拦截,ACTION_MOVE根据情况,决定是否要交给子元素处理。
伪代码:

public boolean onInterceptTouchEvent(MotionEvent event) {    boolean intercepted = false;    int x = (int) event.getX();    int y = (int) event.getY();    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN: {        intercepted = false;        break;    }    case MotionEvent.ACTION_MOVE: {        if (父容器需要当前点击事件) {            intercepted = true;        } else {            intercepted = false;        }        break;    }    case MotionEvent.ACTION_UP: {        intercepted = false;        break;    }    default:        break;    }    mLastXIntercept = x;    mLastYIntercept = y;    return intercepted;}

②内部拦截法,也就是在子元素决定是否将滑动事件消耗掉,如果子元素不滑动,就将滑动事件交由父容器进行处理,不过这种处理方法需要配合requestDisallowInterceptTouchEvent方法才能正常工作,同时父容器需要在onInterceptTouchEvent中设置ACTION_DOWN不被父控件拦截。
子元素伪代码:

public boolean dispatchTouchEvent(MotionEvent event) {    int x = (int) event.getX();    int y = (int) event.getY();    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN: {        mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(true);        break;    }    case MotionEvent.ACTION_MOVE: {        int deltaX = x - mLastX;        int deltaY = y - mLastY;        if (父容器需要此类点击事件) {            mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(false);        }        break;    }    case MotionEvent.ACTION_UP: {        break;    }    default:        break;    }    mLastX = x;    mLastY = y;    return super.dispatchTouchEvent(event);}

父容器伪代码

public boolean onInterceptTouchEvent(MotionEvent event) {    int action = event.getAction();    if (action == MotionEvent.ACTION_DOWN) {        return false;    } else {        return true;    }}
阅读全文
0 0
原创粉丝点击