Android View事件分发机制理解

  为了很好的理解事件分发机制,我们用一个自定义的RelativeLayout,里面装一个自定义的Button,然后分别MyRelativelayout重写里面的dispatchTouchEvent、onInterceptTouchEvent以及onTouchEvent方法,重写MyButton的onTouchEvent以及dispatchTouchEvent。(这里说明一下,因为RelativeLayout是继承ViewGroup的,所以它有拦截机制(onInterceptTouchEvent),但Button是继承是View的,所以没有这个方法),为了方便事件机制理解,这里demo只看ACTION_DOWN事件。

   

   首先都是返回父类的方法,看看返回结果:

   MyRelativeLayout.java

public class MyRelativeLayout extends RelativeLayout {

    public MyRelativeLayout(Context context) {
        super(context);
    }

    public MyRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_DOWN)
            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===onTouchEvent");
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(ev.getAction()==MotionEvent.ACTION_DOWN)
            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(ev.getAction()==MotionEvent.ACTION_DOWN)
            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }
}

MyButton.java

public class MyButton extends Button {
    public MyButton(Context context) {
        super(context);
    }

    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_DOWN)
            Log.d(MyConstants.VIEW_TAG,MyButton.class.getSimpleName()+"===onTouchEvent");
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(ev.getAction()==MotionEvent.ACTION_DOWN)
            Log.d(MyConstants.VIEW_TAG,MyButton.class.getSimpleName()+"===dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }
}

MainActivity调用如下:

    private void testButton() {
        MyRelativeLayout myRelativeLayout = findViewById(R.id.my_relative);
        myRelativeLayout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction()==MotionEvent.ACTION_DOWN)
                    Log.d(MyConstants.VIEW_TAG,"testButton myRelativeLayout====onTouch");
                return false;
            }
        });
        MyButton myButton = findViewById(R.id.my_button);
        myButton.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction()==MotionEvent.ACTION_DOWN)
                    Log.d(MyConstants.VIEW_TAG,"testButton myButton====onTouch");
                return false;
            }
        });
    }

结果如下:

2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent
2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyButton===dispatchTouchEvent
2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: testButton myButton====onTouch
2021-04-05 10:27:35.095 8281-8281/com.jxd.studyone D/VIEW_TAG: MyButton===onTouchEvent

从这里可以分析出来,如果走父类默认的事件分发机制,则先走MyRelativeLayout的分发,拦截,然后给子类消费。

 

假设我们将上述MainActivity调用改为:

 MyButton myButton = findViewById(R.id.my_button);
        myButton.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction()==MotionEvent.ACTION_DOWN)
                    Log.d(MyConstants.VIEW_TAG,"testButton myButton====onTouch");
                return true;
            }
        });

则会返回结果如下:

2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent
2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: MyButton===dispatchTouchEvent
2021-04-05 10:41:11.399 8686-8686/com.jxd.studyone D/VIEW_TAG: testButton myButton====onTouch

事件不再回到MyButton的onTouch

假设我们在MyRelativeLayout拦截这个事件:

   @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(ev.getAction()==MotionEvent.ACTION_DOWN)
            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===onInterceptTouchEvent");
        return true;//super.onInterceptTouchEvent(ev)
    }

则会返回如下结果:

2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent
2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: testButton myRelativeLayout====onTouch
2021-04-05 10:51:57.360 8825-8825/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onTouchEvent

我们可以看到MyButton不会有任何事件响应,事件被我们MyRelativeLayout消费掉了。

 

我们再假设在MyRelativeLayout不再往下分发这个事件:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(ev.getAction()==MotionEvent.ACTION_DOWN)
            Log.d(MyConstants.VIEW_TAG,MyRelativeLayout.class.getSimpleName()+"===dispatchTouchEvent");
        return false;//super.dispatchTouchEvent(ev)
    }

则会返回如下结果:

2021-04-05 10:54:08.848 8922-8922/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent

我们发现事件到dispathTouchEvent之后,就不再放下传递了。

 

同理,我们如果放开MyRelativeLayout的事件分发和拦截,然后修改MyButton的事件分发为false:

则会出现如下结果:

2021-04-05 10:56:03.519 9061-9061/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===dispatchTouchEvent
2021-04-05 10:56:03.519 9061-9061/com.jxd.studyone D/VIEW_TAG: MyRelativeLayout===onInterceptTouchEvent
2021-04-05 10:56:03.519 9061-9061/com.jxd.studyone D/VIEW_TAG: MyButton===dispatchTouchEvent

总结:

1.事件分发是从外层向内层分发

2.从Activity向ViewGroup,再向view进行分发。

3.事件如果不分发,或者被拦截,则子view不会再接收到相应的事件。

至此,我相信各位安卓开发的同学已经知道事件分发机制的来龙去脉了。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

景兄弟1366

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值