Android View的事件分发(一)-事件分发的过程

Android View 虽然不是四大组件,但其并不比四大组件的地位低。而View的核心知识点事件分发机制则是Android开发过程中一个重点也是难点。ScrollView嵌套RecyclerView(或者ListView)的滑动冲突这种问题的理论基础就是事件分发机制。

Android中的事件分发机制也就是View与ViewGroup的对事件的分发与处理。在ViewGroup的内部包含了许多View,而ViewGroup继承自View,所以ViewGroup本身也是一个View。对于事件可以通过ViewGroup下发到它的子View并交由子View进行处理,而ViewGroup本身也能够对事件做出处理。

什么是事件?什么是事件序列?

我们对屏幕的点击,滑动,抬起等一系的动作都是由一个一个MotionEvent对象组成的。根据不同动作,主要有以下三种事件类型:
1.ACTION_DOWN:手指刚接触屏幕,按下去的那一瞬间产生该事件
2.ACTION_MOVE:手指在屏幕上移动时候产生该事件
3.ACTION_UP:手指从屏幕上松开的瞬间产生该事件

上面提到了三种事件ACTION_DOWN、ACTION_MOVE和ACTION_UP。它们都是单独的事件,而事件序列由它们组成。一个事件序列指的是:由一个ACTION_DOWN事件,0个或者1个或者多个ACTION_MOVE事件,加上一个ACTION_UP事件组成的一个序列。

事件是用户与屏幕发生交互时产生的,而Activity则是Android中负责与用户发生交互的组件。所以事件的传递,首先是到达Activity,再通过内部传递之后,到达我们的布局文件中的layout和View。事件发生之后,需要进行响应处理,再传递的过程中,由上往下,都有可能有机会处理一个事件序列。如果从Activity往下,到最终的View,事件都没有得到处理,则事件又从下往上,回到Activity,如果回到Activity之后,Activity没有处理这个事件,那么这个事件就会自动结束。

下面简单看下三个事件方法:

mButton.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        e("MotionEvent: ACTION_DOWN");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        e("MotionEvent: ACTION_MOVE");
                        break;
                    case MotionEvent.ACTION_UP:
                        e("MotionEvent: ACTION_UP");
                        break;
                }
                return false;
            }
        }); 

定义一个按钮,设置触摸事件,根据手指的触发,执行不同的类型是事件。

事件分发的三个方法:

dispatchTouchEvent:用于分发传递事件,只要事件能够传递到当前View,这个方法就会被调用。

onInterceptTouchEvent:用于判断是否拦截事件,不往下传递。(此方法只有ViewGroup拥有,Activity和View没有)此方法在dispatchTouchEvent方法中调用。

onTouchEvent:用于处理事件,同样也是在dispatchTouchEvent方法中调用。

ViewGroup的事件分发方法:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    show("dispatchTouchEvent",ev);
    //switch
    return super.dispatchTouchEvent(ev);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    show("onInterceptTouchEvent",ev);
    //switch
    return super.onInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    show("onTouchEvent",event);
    return super.onTouchEvent(event);
} 

View的事件分发方法:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    show("dispatchTouchEvent",event);
    //switch
    return super.dispatchTouchEvent(event);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    show("onTouchEvent",event);
    //switch
    return super.onTouchEvent(event);
} 

View是最后的事件处理,所以没有拦截事件。

dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev)

1)return true: 表示消耗了当前事件,有可能是当前 View 的 onTouchEvent 或者是子 View 的 dispatchTouchEvent消费了,事件终止,不再传递。

2)return false: 调用父 ViewGroup 或 Activity 的 onTouchEvent。 (不再往下传)。

3)return super.dispatherTouchEvent: 则继续往下(子 View )传递,或者是调用当前 View 的 onTouchEvent 方法;

总结: 用来分发事件,即事件序列的大门,如果事件传递到当前 View 的 onTouchEvent或者是子 View 的 dispatchTouchEvent,即该方法被调用了。 另外如果不消耗 ACTION_DOWN 事件,那么 down, move, up 事件都与该 View 无关,交由父类处理(父类的 onTouchEvent 方法)

onInterceptTouchEvent

public boolean onInterceptTouchEvent(MotionEvent ev)

1)return true: ViewGroup 将该事件拦截,交给自己的 onTouchEvent 处理。

2)return false: 继续传递给子元素的 dispatchTouchEvent 处理。

3)return super.dispatherTouchEvent: 事件默认不会被拦截。

总结: 在 dispatchTouchEvent 内部调用,顾名思义就是判断是否拦截某个事件。(注:ViewGroup 才有的方法,View 因为没有子View了,所以不需要也没有该方法) 。而且这一个事件序列(当前和其它事件)都只能由该 ViewGroup 处理,并且不会再调用该 onInterceptTouchEvent 方法去询问是否拦截。

onTouchEvent

public boolean onTouchEvent(MotionEvent ev)

1)return true: 事件消费,当前事件终止。

2)return false: 交给父 View 的 onTouchEvent。

3)return super.dispatherTouchEvent: 默认处理事件的逻辑和返回 false 时相同。

总结: 在dispatchTouchEvent内部调用

上面3个方法的关系,可以用下面的方法表示:

public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean consume = false;//事件是否被消费
        if (onInterceptTouchEvent(ev)){//调用 onInterceptTouchEvent 判断是否拦截事件
            consume = onTouchEvent(ev);//如果拦截则调用自身的onTouchEvent方法
        }else{
            consume = child.dispatchTouchEvent(ev);//不拦截调用子View的dispatchTouchEvent方法
        }
        return consume;//返回值表示事件是否被消费,true事件终止,false调用父View的onTouchEvent方法
    } 

View的事件分发也是一个顺序执行的操作,自上而下传递,自下而上的回调,直到在某个地方被消费了,下面会按照事件分发的顺序,依次介绍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值