关闭

Android事件分发机制

标签: android
24人阅读 评论(0) 收藏 举报
分类:

Android 事件分发机制

事件传递分发过程

  • Activity ————> Window ————> PhoneWindow ————> decorView ————> rootView
  • 可以通过 getWindow().getDecorView() 获取 setContentView 所设置 View

这里写图片描述


/**
 * 通过伪代码表达事件分发
 */
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    boolean consume = false;
    if(onInterceptTouchEvent(event)) {
        consume = onTouchEvent(event);
    }else {
        consume = child.dispatchTouchEvent(event);
    }
    return super.dispatchTouchEvent(event);
}


public class MyViewGroup extends ViewGroup {

    public MyViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

    }


    /**
     * 分发 TouchEvent, 返回
     *    true  : 不往下分发 TouchEvent 事件, 交给自己的 onTouchEvent 函数处理
     *    false : 向下分发 TouchEvent 事件, 交给自己的 onInterceptTouchEvent 函理
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }


    /**
     * 是否拦截 TouchEvent, 根据返回值决定 :
     *    true 拦截 TouchEvent, 交给自己的 onTouchEvent 函数处理
     *    false 不拦截 TouchEvent, 将事件传递给子 View 的 dispatchTouchEvent
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    /**
     * 处理TouchEvent, 返回 
     *    true 自己处理
     *    false 交给父控件处理, 如果没有父控件则事件会丢失
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
}


事件冲突类型

  1. 外部滑动方向和内部滑动方向不一致
  2. 外部滑动方向和内部滑动方向一致
  3. 以上两种情况嵌套


事件冲突解决方法

  1. 外部拦截法, 通过重写父容器的 onInterceptTouchEvent() 方法处理
  2. 内部拦截法, 结合 getParent().requestDisallowInterceptTouchEvent(disallowIntercept) 方法

外部拦截法

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

    boolean intercepted = false;

    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
        intercepted = false;  // ACTION_DOWN 事件拦截会直接把 ACTION_MOVE 和 ACTION_UP 也交给当前 View 处理
        break;

    case MotionEvent.ACTION_MOVE:
        if(true) {
            intercepted = true;   // 父容器需要当前点击事件
        }else {
            intercepted = false;
        }
        break;

    case MotionEvent.ACTION_UP:
        intercepted = false;     // ACTION_UP 事件实际使用用处不大,通常返回 false
        break;
    }
    return intercepted;
}

内部拦截法


@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
        // 请求父容器不要拦截事件,父容器不能 ACTION_DOWN 事件,否则该方法无效
        getParent().requestDisallowInterceptTouchEvent(true);   
        break;

    case MotionEvent.ACTION_MOVE:
        if(true) {   // 如果是父容器需要点击事件
            // 父容器要默认拦截 ACTION_DOWN 事件以外的事件
            getParent().requestDisallowInterceptTouchEvent(false);
        }
        break;
    }
    return super.dispatchTouchEvent(ev);
}



/**
 * 父容器的拦截器
 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return ev.getAction() == MotionEvent.ACTION_DOWN ? false : true;
}

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:94次
    • 积分:22
    • 等级:
    • 排名:千里之外
    • 原创:1篇
    • 转载:0篇
    • 译文:2篇
    • 评论:0条
    文章分类
    文章存档