Android View触摸事件传递机制 一

Android View触摸事件传递机制 一

最近在工作中遇到了这方面的需求, 对这方面一开始虎头虎脑的搞了好几天, 总感觉这方面的知识点不太容易被理解(今早看了下午就忘了), 理解不透彻, 主要记录下来。

  • 前提说明: 视图控件共分为两种(ViewGroup + View)两种的触摸机制大致类似也有一定的区分, 该篇博文主要针对View的事件分发。 ViewGroup的应该会在下篇说明。

  • 该篇博文主要针对现象讲解, 先把整体的脉络将通了, 下篇博文将会主打这些脉络的源码的解释。


主要方法提要

public boolean dispatchTouchEvent(MotionEvent event)
* 用来进行事件的分发, 只要用户触摸到该View并且能把事件传递到该View中, 该方法将会被第一个调用;

public void setOnTouchListener(OnTouchListener l)
* 需要重写该监听器的onTouch方法, 如果用户设置了, 按照正常的逻辑, dispathTouchEvent会将事件优先分发到该函数中

public boolean onTouchEvent(MotionEvent event)
* 该函数是否回调取决于onTouch的返回值,如果onTouch返回true: 证明事件已被拦截, 该函数将不会被调用。 如果返回false, 继续进行事件分发。

public void setOnClickListener(@Nullable OnClickListener l)
* 需要重写该监听器的onClick方法, 该函数回调在onTouchEvent的case ACTION_UP中执行。

小总结

  • 如果onTouch返回true, onTouchEvent将不会调用
  • onClick方法在onTouchEvent方法中调用
  • dispatchTouchEvent优先级最高, 其次为onTouch, 之后为onTouchEvent, onClick的接受优先级别最低。
  • onClick方法在一系列的事件传递中, 事件回调的优先级最低, 处于事件传递的最底层

伪码

public boolean dispatchTouchEvent(MotionEvent event){
    if(!onTouch()){
        onTouchEvent()
    }
}

public boolean onTouchEvent(MotionEvent event){
    switch(event.getAction())
    {
        case MotionEvent.ACTION_UP:
            onClick(View v);
        break;
    }
}

通过上述伪码很容易看出View的事件触摸分发机制

大白话讲述分发流程

当触摸事件产生后, 这时View的dispatchTouchEvent会首先触发,如果给这个View设置了onTouchListener并且onTouch返回true, 即事件分发机制到此结束;如果没有设置onTouchListener或者onTouch返回false时, 触摸事件将会分发到onTouchEvent函数中, onTouchEvent将会在ACTION_UP中判断当前View是否有设置onClickListener, 如果有则调用onClick函数。

注意: View的onClick会调用的前提是当前View是可点击的, 并且当前View接受了事件序列中的down和up事件。

源代码分析实战

public class MyView extends Button {
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d("zxc", "button,  dispathTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("zxc", "button, onTouchEvent");
        return super.onTouchEvent(event);
    }
}

myView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Log.d("zxc", "button, onTouch...");
        return false;
    }
});

myView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("zxc", "button, onClick...");
    }
});

上诉代码简单的重写了View, 并且设置了onTouchListener与onClickListener; 在我们所有方法都用默认的情况下, 点击MyView控件后, 打印出来的log为:

06-19 19:51:03.202 20258-20258/? D/zxc: button,  dispathTouchEvent
06-19 19:51:03.202 20258-20258/? D/zxc: button, onTouch...
06-19 19:51:03.202 20258-20258/? D/zxc: button, onTouchEvent
06-19 19:51:03.204 20258-20258/? D/zxc: button,  dispathTouchEvent
06-19 19:51:03.204 20258-20258/? D/zxc: button, onTouch...
06-19 19:51:03.204 20258-20258/? D/zxc: button, onTouchEvent
06-19 19:51:03.218 20258-20258/? D/zxc: button, onClick...

通过log可以看到, dispatchTouchEvent优先级最高, 其次为onTouch,然后使onTouchEvent。
该log的现象, 我只简单的按下和抬起(ACTION_DOWN、ACTION_UP), onClick在onTouchEvent的ACTION_UP中回调;

当我们把onTouch的返回值修改为true时;

 myView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Log.d("zxc", "button, onTouch...");
        // return false;
        return true;
    }
});

跟上诉同样的按下和抬起后的log为:

06-19 19:57:47.693 22863-22863/? D/zxc: button,  dispathTouchEvent
06-19 19:57:47.694 22863-22863/? D/zxc: button, onTouch...
06-19 19:57:47.712 22863-22863/? D/zxc: button,  dispathTouchEvent
06-19 19:57:47.712 22863-22863/? D/zxc: button, onTouch...

当onTouch返回true时, 表示该事件序列已被处理, 整体的事件不继续往下传递(onTouchEvent方法没有调用);

将onTouch的返回值重新修改为return false;
修改dispatchTouchEvent的返回值为false;

 @Override
public boolean dispatchTouchEvent(MotionEvent event) {
    Log.d("zxc", "button,  dispathTouchEvent");
    super.dispatchTouchEvent(event);
    return false;
}

跟上诉同样的按下和抬起后的log为:

06-19 20:02:38.249 25326-25326/? D/zxc: button,  dispathTouchEvent
06-19 20:02:38.249 25326-25326/? D/zxc: button, onTouch...
06-19 20:02:38.249 25326-25326/? D/zxc: button, onTouchEvent

可以看到, 事件序列中, 仅仅派发了ACTION_DOWN事件, ACTION_MOVE和ACTION_UP等都没有继续分发。

通过该现象我们可以得出结论, dispatchTouchEvent方法是进行事件派发传递的, 如果dispatchTouchEvent方法返回false, 那么将会停止继续派发同事件序列中的下个事件了;

总结View的事件分发传递

  1. 首先执行View的dispatchTouchEvent方法进行事件分发
  2. 如果dispatchTouchEvent方法返回false, 那么同事件序列中将不会再进行事件的传递
  3. 如果控件的onTouch返回true, 那么将不会调用onTouchEvent和onClick函数的回调

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值