View的事件传递机制总结

本文详细解析了Android中触摸事件的处理流程,包括dispatchTouchEvent、onTouch、onTouchEvent和onClick方法的作用与交互关系。重点阐述了如何通过设置onTouch监听器控制事件流,并在不可点击状态下避免执行onTouchEvent和onClick事件。通过实例展示了不同触摸状态下的事件执行顺序,以及onTouch方法返回值对事件流程的影响。

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

涉及到的方法(按顺序)

  1. dispatchTouchEvent
  2. setOnTouchListener的onTouch
  3. onTouchEvent
  4. onClick
  5. onClick是在ACTION_UP执行完才执行的

我们看看dispatchTouchEvent的源码:

  public boolean dispatchTouchEvent(MotionEvent event) {
        if (!onFilterTouchEventForSecurity(event)) {
            return false;
        }

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

首先判断当mOnTouchListener不为空并且当前控件是enable的并且onTouch方法返回true,则不再执行onTouchEvent方法,

那么这个mOnTouchListener是什么

  public void setOnTouchListener(OnTouchListener l) {
        mOnTouchListener = l;
    }

使我们通过setOnTouchListener方法传进去的,我们一般这样写:

 mButton.setOnTouchListener(new OnTouchListener()  
        {  
            @Override  
            public boolean onTouch(View v, MotionEvent event)  
            {  
                int action = event.getAction();  

                switch (action)  
                {  
                case MotionEvent.ACTION_DOWN:  
                    Log.e(TAG, "onTouch ACTION_DOWN");  
                    break;  
                case MotionEvent.ACTION_MOVE:  
                    Log.e(TAG, "onTouch ACTION_MOVE");  
                    break;  
                case MotionEvent.ACTION_UP:  
                    Log.e(TAG, "onTouch ACTION_UP");  
                    break;  
                default:  
                    break;  
                }  

                return false;  
            }  
        });  

这个方法如果返回true,表示事件被消费,那么onTouchEvent方法不会执行。

总结:

  1. onTouch接口方法的返回值决定是否执行onTouchEvent方法。
  2. 只要onTouch接口方法返回值为true,dispatchTouchEvent方法一定返回true,否则根据onTouchEvent方法返回值决定dispatchTouchEvent返回值。
public void setOnClickListener(OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        mOnClickListener = l;
    }

总结:
1.只要给任何一个View设置了setOnClickListener点击监听事件,不管这个View是否是可点击的状态,最后都设置为了可点击的状态了。

2.只有当前View是可点击或者长按的状态,才进入if条件判断,然后执行相应的手势操作,最后返回true。也就是说,只要View是可点击的,onTouchEvent方法返回的就是true,从而dispatchTouchEvent方法返回的也是true。

3.只要是当前View是不可点击或者长按的状态,if条件不成立,不执行任何操作,直接返回false。也就是说,View不可点击的时候,onTouchEvent方法返回的就是false,从而dispatchTouchEvent方法返回的也是false。

4.onClick方法是在ACTION_UP手势里面执行的,也就是当手势抬起时才去执行onClick方法。

onTouch方法返回值为true

button.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        Log.e(TAG, "onTouch------->>ACTION_DOWN");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.e(TAG, "onTouch------->>ACTION_MOVE");
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.e(TAG, "onTouch------->>ACTION_UP");
                        break;
                }
                return true;
            }
        });

这里写图片描述

当onTouch方法返回true时,就不执行onTouchEvnet方法,因此也就不执行onClick点击事件。可以理解成此时onTouch把触摸事件已经消费掉了,也就不会继续往下传递触摸事件。所以如果你不想自己的View执行onTouchEvent方法,你可以设置onTouch事件,且返回值为true即可。

View不可点击情况

public class MainActivity extends Activity {
    private MyCustomView button;
    private String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (MyCustomView) findViewById(R.id.button);

        Log.e(TAG, "the view is clickable " + button.isClickable());

//        button.setClickable(true);

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

//        button.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                Log.e(TAG, "onClick------->>onClick");
//            }
//        });
    }
}

这里写图片描述
不知道你发现木有?此处打印看出只执行了ACTION_DOWN手指操作,其他的手势操作呢?没有执行,为什么呢?
情况是这样的:当onTouch方法返回false,则dispatchTouchEvent方法就会执行onTouchEvent方法,但是由于View不可点击,所以onTouchEvent是不执行if条件体的,也就是onTouchEvent方法返回false,从而导致dispatchTouchEvent方法返回false,由于dispatchTouchEvent方法返回false,导致后面的手势操作ACTION_MOVE,ACTION_UP得不到执行。

总结:如果我们将手势操作分为三个过程的话:ACTION_DOWN,ACTION_MOVE,ACTION_UP。只有当dispatchTouchEvent方法返回true时,系统才会执行对应过程后面的手势操作。

最后来一张流程图

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值