Android自定义View总结(二)事件分发机制

新建了一个qq群 482543750,欢迎一起学习Android的小伙伴加入。

提供各种Android学习资料,面试资料,Android简历模板。



本文将介绍View的核心知识:事件分发机制

分析事件分发机制,实际上就是分析MotionEvent,即点击事件。
当一个MotionEvent产生之后,系统需要把这个事件传递给一个View,传递的过程就是 分发过程
这涉及到三个核心方法

public void dispatchTouchEvent(MotionEvent ev)
用来进行事件的分发,如果事件能够传递给当前View,那么此方法 一定会被调用
返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。

public void onInterceptTouchEvent(MotionEvent ev)
在dispatchTouchEvent()方法的内部进行调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列中,此方法不会被再次调用。
返回结果表示是否拦截当前事件。

public void onTouchEvent(MotionEvent ev)
在dispatchTouchEvent()方法中调用,用来处理点击事件。
返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件。

1、点击事件的传递规则,可以大致这样理解:
对于一个根ViewGroup,当点击事件发生以后,首先传递给它,这时,首先调用dispatchTouchEvent()方法。
此时,如果onInterceptTouchEvent()返回true,表示它要拦截当前事件(即要对当前事件进行处理),此时它的onTouchEvent()方法就会被调用
如果onInterceptTouchEvent()返回false,表示不拦截当前事件,那么当前事件就会传递给它的子元素,子元素的dispatchTouchEvent()方法就会被调用。
如此反复,直到事件被最终处理。

以下伪代码展示了这个过程

public boolean dispatchTouchEvent(MotionEvent ev){
    boolean consume = false;
    //假如要拦截当前事件
    if (onInterceptTouchEvent(ev)){
        onTouchEvent(MotionEvent ev);
    }else {
        //不拦截当前事件
        consume = child.dispatchTouchEvent(ev);
    }
return consume;
}

2、事件的传递过程
当一个点击事件产生后,它的传递过程为:Activity->Window->View,
点击事件总是先传递给Activity,再传递给Window,最终传递给顶级View。
顶级View接收到事件后,按照事件分发机制去分发事件。
假如一个View的onTouchEvent()方法返回false,表示它不处理这个事件,那么其父容器的onTouchEvent()方法将被调用。
若所有元素都不处理事件,最终事件会传递给Activity处理

3、事件传递的优先级问题

一个View要处理事件,假如我们给自定义View设置onTouchListener,如下
public class MyListentr implements  OnTouchListener{

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return false;
    }
}
那么其onTouch()方法会被调用,可以看到,默认返回false。
假如返回false,那么当前View的onTouchEvent()方法会被调用;
如果返回true,那么onTouchEvent()方法不会被调用,也就是说,我们在onTouchEvent()中写的处理逻辑将失效。
可见,onTouchListener()比onTouchEvent()优先级要高。

此外,onClickListener()方法优先级最低。

4、关于事件分发机制的一些概念和结论:

(1)同一个事件序列,指的是,在手指触摸屏幕起,到手指离开屏幕结束的过程,在此期间产生的一些列事件,以down事件开始,中间包含数量不等的move事件,up事件作为结束。

(2)一个事件序列只能被一个View拦截,消耗。因为一个元素一旦拦截了某个事件,改事件序列内的所有事件都会交给它处理。但通过特殊手段,比如,在进行拦截的View的onTouchEvent()方法中强行传递给其他View进行处理,可以实现一个以上的View共同处理事件。

(3)一个View决定进行拦截某事件后,它的onInterceptTouchEvent()不会再被调用(即只会在刚开始决定是否拦截时调用一次),因为同一序列的其它方法都会交给它进行处理,不用再进行判断。

(4)一个View开始处理事件,如果它不消耗down事件,即onTouchEvent返回了false,那么同一事件序列的其他事件都不会再交给它处理,而重新交给其父元素进行处理。

(5)若View不消耗除down事件意外的其他事件,那么这个点击事件将消失,但父元素的onTouchEvent()不会被调用,当前View可以接收到后续事件,而消失的点击事件将被传递给Activity处理

(6)ViewGroup默认不处理任何事件,源码中ViewGroup的onInterceptTouchEvent()默认返回false

(7)View没有onInterceptTouchEvent()方法,一旦有事件传递给它,它的onTouchEvent方法就会被调用



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值