Android 事件分发机制

本文详细解析了Android事件分发机制,包括Activity、ViewGroup、View三个主体的交互,dispatchTouchEvent、onTouchEvent等六个关键事件的处理流程,以及MotionEvent.ACTION_DOWN等三个核心流程的运作原理。通过实例代码和流程图,深入理解事件分发机制中的优先级和执行逻辑。

Android 事件分发机制

口诀: 3个主体6件事,3个流程负责制
  • 三个主体: Activity , ViewGroup, View
  • 六件事:dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent,requestDisallowInterceptTouchEvent,onTouchListener,onClickListener
  • 三个流程: MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP
  • 负责制:负责到底只要事处理了流程中的ACTION_DOWN的事件的主体return true,后面的整个都要交给它处理

流程图:https://www.jianshu.com/p/e99b5e8bd67b

流程图的解释请参考,参考的说明里面:https://www.jianshu.com/p/e99b5e8bd67b
这里需要注意的: 在这里插入图片描述

  • 1: activity 如果dispatchTouchEvent不是return的super 那么都会丢弃,不会再往下传递,也不会触发onTouchEvent的事件
  • 2: 执行优先级 onTouchListener >onTouchEvent>onClickListener 如果onTouchListener 的回调onTouch里面 返回的是true那么不会执行onTouchEvent
public boolean onTouchEvent(MotionEvent event) {
            
   case MotionEvent.ACTION_UP:
...
    if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
        // This is a tap, so remove the longpress check
    removeLongPressCallback();

     // Only perform take click actions if we were in the pressed state
     if (!focusTaken) {
        // Use a Runnable and post this rather than calling
        // performClick directly. This lets other visual state
        // of the view update before click actions start.
        if (mPerformClick == null) {
            mPerformClick = new PerformClick();
        }
        if (!post(mPerformClick)) {
            performClickInternal();
        }
    }
}
    ...
}
mMyView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("kodulf","View on click listener");
            }
        });

        mMyView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.d("kodulf","View on touch listener");
                return false;
            }
        });
执行结果:
 D/kodulf: part: =============Activity method:[-dispatchTouchEvent -] action:DOWN 
 D/kodulf: part: -- LinearLayout -- method:[- dispatchTouchEvent  -] action:DOWN 
 D/kodulf: part: -- LinearLayout -- method:[-MotionEvent -] action:DOWN 
 D/kodulf: part: -- LinearLayout -- method:[- dispatchTouchEvent  -] action:DOWN 
 D/kodulf: part: -- LinearLayout -- method:[-MotionEvent -] action:DOWN 
 D/kodulf: part: ++++ My View  method:[- dispatchTouchEvent  -] action:DOWN 
 D/kodulf: View on touch listener
 D/kodulf: part: ++++ My View  method:[-onTouchEvent -] action:DOWN 
 D/kodulf: part: =============Activity method:[-dispatchTouchEvent -] action:UP 
 D/kodulf: part: -- LinearLayout -- method:[- dispatchTouchEvent  -] action:UP 
 D/kodulf: part: -- LinearLayout -- method:[-MotionEvent -] action:UP 
 D/kodulf: part: -- LinearLayout -- method:[- dispatchTouchEvent  -] action:UP 
 D/kodulf: part: -- LinearLayout -- method:[-MotionEvent -] action:UP 
 D/kodulf: part: ++++ My View  method:[- dispatchTouchEvent  -] action:UP 
 D/kodulf: View on touch listener
 D/kodulf: part: ++++ My View  method:[-onTouchEvent -] action:UP 
 D/kodulf: View on click listener    
  • 3: requestDisallowInterceptTouchEvent 这个必须是使用getParent().requestDisallowInterceptTouchEvent. 但是它对ACTION_DOWN 是无效的,因为如果没有ACTION_DOWN传递过来的话,它怎么执行呢?

实例

1.0 事件分发的 demo

1.1 ViewPager 和 SlidingPanelLayout 的滑动冲突的解决
 @Override
    public boolean onTouchEvent(MotionEvent ev) {

        float rawX = ev.getRawX();
        int width = getWidth();
        if(rawX >=width/10)
            if(ev.getAction() == MotionEvent.ACTION_DOWN)
            getParent().requestDisallowInterceptTouchEvent(true);

        return super.onTouchEvent(ev);
    }
  • 2: 也可以自定SlidingPanelLayout 在他的事件拦截里面执行:
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        float rawX = ev.getRawX();
        int width = getWidth();
        if(rawX <width/10||rawX>(width*9)/10)
            return super.onInterceptTouchEvent(ev);
        else
            return false;
    }
  • 3: 顺便说一下:DrawerLayout 是不需要去写这个的,因为他内部嵌入了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值