Android事件分发机制(一)

本文聚焦Android中View的事件分发机制。作者通过点击Button按钮查看事件流程,总结出大体流程为dispatchTouchEvent-->onTouchListener---return false-->onTouchEvent。还分析了dispatchTouchEvent和onTouchEvent返回不同值时的情况,强调了super.dispatchTouchEvent(event)调用的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一直对事件分发的源码不是特别了解,今天重点关注了一下,感觉有点自己的体会吧,写下来记录一下心得。

事件分发大体可以分为View的事件分发和ViewGroup的事件分发,我们先来查看下比较简单点的View的事件

1、事件流程

我们首先通过点击一个Button按钮,查看一下Button的事件怎么走的:

public class MyButton extends Button {

    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("ricky", "dispatchTouchEvent:action--"+event.getAction()+"---view:MyButton");
        return super.dispatchTouchEvent(event);
//		return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("ricky", "onTouchEvent:action--"+event.getAction()+"---view:MyButton");
        return super.onTouchEvent(event);
    }
}

我们在activity里面实现下面这俩个方法 

 @Override
    public void onClick(View v) {
        Log.i("ricky", "OnClickListener----view:"+v);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Log.i("ricky", "OnTouchListener:acton--"+event.getAction()+"----view:"+v);
        return false;
    }

打印结果:

06-19 13:11:15.350 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:11:15.422 24121-24121/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
 

我们可以总结一下大体的流程为:ispatchTouchEvent-->onTouchListener---return false-->onTouchEvent 

下面我们可以猜想一下如果我在 dispatchTouchEvent 方法里面返回true和false会有什么区别,我们带着猜想看下核心源码:

public boolean dispatchTouchEvent(MotionEvent event) {
    ...

    if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
    }
    ...
}

我们可以在其中发现dispatchTouchEvent方法返回值取决于mOnTouchListener、和onTouchEvent和ENABLED。

如果view为disenable,则:onTouchListener里面不会执行,但是会执行onTouchEvent(event)方法;

如果onTouch方法返回true,表示消耗这次事件。down会执行,但是up事件是无法到达onClickListener;

如果onTouch方法返回false,不会消耗此事件。

下面我们通过打印看下我们分析的对不对:

1、dispatchTouchEvent 返回super.dispatchTouchEvent(event);    onTouchEvent 返回false //super.onTouchEvent(event);

06-19 13:25:27.884 28410-28410/com.example.shijiantest I/ricky: dispatchTouchEvent:action--0
06-19 13:29:25.648 30033-30033/com.example.shijiantest I/ricky: super.dispatchTouchEvent(event)--false
06-19 13:25:27.885 28410-28410/com.example.shijiantest I/ricky: OnTouchListener:acton--0----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ........ 0,0-264,144 #7f070022 app:id/button}
06-19 13:25:27.885 28410-28410/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:25:27.899 28410-28410/com.example.shijiantest I/ricky: OnTouchListener:acton--0----view:android.widget.LinearLayout{416a794 V.E...C.. .......D 0,0-1080,1680 #7f07004a app:id/layout}
06-19 13:25:27.969 28410-28410/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:android.widget.LinearLayout{416a794 V.E...C.. ...P.... 0,0-1080,1680 #7f07004a app:id/layout}
06-19 13:25:27.970 28410-28410/com.example.shijiantest I/ricky: OnClickListener----view:android.widget.LinearLayout{416a794 V.E...C.. ...P.... 0,0-1080,1680 #7f07004a app:id/layout}
 

2、 dispatchTouchEvent 返回super.dispatchTouchEvent(event);    onTouchEvent  返回true //super.onTouchEvent(event);

06-19 13:26:50.939 28986-28986/com.example.shijiantest I/ricky: dispatchTouchEvent:action--0
06-19 13:29:25.648 30033-30033/com.example.shijiantest I/ricky: super.dispatchTouchEvent(event)--true
06-19 13:26:50.939 28986-28986/com.example.shijiantest I/ricky: OnTouchListener:acton--0----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ........ 0,0-264,144 #7f070022 app:id/button}
06-19 13:26:50.939 28986-28986/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:26:51.049 28986-28986/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
 

 可以发现当我们在onTouchEvent 返回true是会执行消耗这次事件,当onTouchEvent返回false时不会执行view的onTouch事件,而是执行的父类的事件。

3、dispatchTouchEvent 返回true super.dispatchTouchEvent(event);

dispatchTouchEvent true super.dispatchTouchEvent(event);     onTouchEvent true super.onTouchEvent(event);
06-19 13:11:15.350 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: OnTouchListener:acton--1view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:11:15.420 24121-24121/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:11:15.422 24121-24121/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}

dispatchTouchEvent true super.dispatchTouchEvent(event);    onTouchEvent false super.onTouchEvent(event);
06-19 13:13:11.212 24697-24697/com.example.shijiantest I/ricky: onTouchEvent:action--0
06-19 13:13:11.312 24697-24697/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1
06-19 13:13:11.313 24697-24697/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 13:13:11.313 24697-24697/com.example.shijiantest I/ricky: onTouchEvent:action--1
06-19 13:13:11.315 24697-24697/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
 

我们发现不管 onTouchEvent返回true或false都会执行OnClickListener事件,反之都走的父类的事件。

还有个重要的问题,我在测试的时候发现

@Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("ricky", "dispatchTouchEvent:action--"+event.getAction()+"---view:MyButton");
        super.dispatchTouchEvent(event);
    	return false;
    }

我们经常会漏掉super.dispatchTouchEvent(event);这个调用,这个是走的父布局的方法,如果我们不去调用那么我们的dispatchTouchEvent就没有什么意义啦。当然也是视情况而定,我们一般会调用这个方法,否则会经常出现一些奇怪的现象。

今天就主要介绍下View的事件吧,下篇在去做ViewGroup的总结。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值