Android有意思的事件分发

目录

Button有设置OnClickListener

Button没有设置onClickListener


假设有这么一道题目,ScrollView里面包着Button,描述上滑的完整事件。

我们构建一个布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.plbear.leakcanary.MyScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:id="@+id/btn_1"
                android:text="Button1" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button2" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button3" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button4" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button5" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button6" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button7" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button8" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button9" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button10" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button11" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button12" />

            <com.plbear.leakcanary.MyButton
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:text="Button13" />
        </LinearLayout>
    </com.plbear.leakcanary.MyScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

我们自定义MyScrollView和MyButton,在关键方法里面加上日志而已

package com.plbear.leakcanary

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent

class MyButton @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, style: Int = 0)
    : androidx.appcompat.widget.AppCompatButton(context, attributeSet, style) {
    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        logcat("MyButton dispatchTouchEvent in :" + ev.getActionName())
        val result = super.dispatchTouchEvent(ev)
        logcat("MyButton dispatchTouchEvent:" + ev.getActionName() + " return:" + result)
        return result
    }

    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        val result = super.onTouchEvent(ev)
        logcat("MyButton onTouchEvent:" + ev.getActionName() + " return:" + result)
        return result
    }
}
package com.plbear.leakcanary

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ScrollView
import java.lang.Exception

class MyScrollView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, style: Int = 0)
    : ScrollView(context, attributeSet, style) {
    var isPrintMove = false

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        logcat("scrollView dispatchTouchEvent in :" + ev.getActionName())
        val result = super.dispatchTouchEvent(ev)
        logcat("scrollView dispatchTouchEvent:" + ev.getActionName() + " return:" + result)
        return result
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        logcat("scrollView onInterceptTouchEvent in :" + ev.getActionName())
//        logcat(Exception("scrollView onInterceptTouchEvent"))
        val result = super.onInterceptTouchEvent(ev)
        logcat("scrollView onInterceptTouchEvent:" + ev.getActionName() + " return:" + result)
        return result
    }

    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        val result = super.onTouchEvent(ev)
        logcat("scrollView onTouchEvent:" + ev.getActionName() + " return:" + result)
        if (ev?.action == MotionEvent.ACTION_MOVE && !isPrintMove){
            isPrintMove = true
//            logcat(Exception("scrollView onTouchEvent Stack"))
        }
        return result
    }
}

这个时候分为Button有OnClickListener和没有OnClickListener两种情况。

Button有设置OnClickListener

完整的事件日志如下

2021-04-05 20:29:15.920 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_DOWN
2021-04-05 20:29:15.920 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent in :ACTION_DOWN
2021-04-05 20:29:15.920 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent:ACTION_DOWN return:false
2021-04-05 20:29:15.921 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent in :ACTION_DOWN
2021-04-05 20:29:15.921 8398-8398/com.plbear.leakcanary E/yanlog: MyButton onTouchEvent:ACTION_DOWN return:true
2021-04-05 20:29:15.921 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent:ACTION_DOWN return:true
2021-04-05 20:29:15.922 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_DOWN return:true

//上面是Down事件的处理,可以看到Down事件依次通过父View的dispatchTouchEvent onInterceptTouchEvent分发到子View的onTouchEvent。子View表示对Down事件进行拦截
2021-04-05 20:29:16.122 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.122 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.122 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent:ACTION_MOVE return:false
2021-04-05 20:29:16.122 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.122 8398-8398/com.plbear.leakcanary E/yanlog: MyButton onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.122 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.122 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.138 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.138 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.138 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent:ACTION_MOVE return:false
2021-04-05 20:29:16.138 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.138 8398-8398/com.plbear.leakcanary E/yanlog: MyButton onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.138 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.138 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.155 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.156 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.156 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent:ACTION_MOVE return:false
2021-04-05 20:29:16.156 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.156 8398-8398/com.plbear.leakcanary E/yanlog: MyButton onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.156 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent:ACTION_MOVE return:true

// 一直到这里,MOVE事件和Down事件的处理一样。MyButton表示我来处理MOVE事件
2021-04-05 20:29:16.156 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.172 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.172 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.173 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent:ACTION_MOVE return:true

//到这里,父View,也就是ScrollView的onInterceptTouchEvent表示我要拦截move事件了,所以这个时候给Button一个CANCEL事件
2021-04-05 20:29:16.173 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent in :ACTION_CANCEL
2021-04-05 20:29:16.173 8398-8398/com.plbear.leakcanary E/yanlog: MyButton onTouchEvent:ACTION_CANCEL return:true
2021-04-05 20:29:16.173 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent:ACTION_CANCEL return:true
2021-04-05 20:29:16.173 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.189 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.190 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_MOVE return:true

// ScrollView开始处理MOVE事件
2021-04-05 20:29:16.190 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.206 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:29:16.209 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:29:16.209 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
。。。 这里忽略很多Move事件
2021-04-05 20:29:16.782 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_UP
2021-04-05 20:29:16.782 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_UP return:true
2021-04-05 20:29:16.782 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_UP return:true

//ScrollView处理完UP事件
 

Button没有设置onClickListener

这里表示Button表示我压根就不处理Click事件,那整个Touch都与我无关

2021-04-05 20:44:24.128 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_DOWN
2021-04-05 20:44:24.128 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent in :ACTION_DOWN
2021-04-05 20:44:24.128 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onInterceptTouchEvent:ACTION_DOWN return:false
2021-04-05 20:44:24.129 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent in :ACTION_DOWN
2021-04-05 20:44:24.129 8398-8398/com.plbear.leakcanary E/yanlog: MyButton onTouchEvent:ACTION_DOWN return:false //注意这里Button的Down返回了false,与上面不同。Button表示down事件我也不处理。
2021-04-05 20:44:24.129 8398-8398/com.plbear.leakcanary E/yanlog: MyButton dispatchTouchEvent:ACTION_DOWN return:false
2021-04-05 20:44:24.130 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_DOWN return:true
2021-04-05 20:44:24.130 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_DOWN return:true //因为Button不处理Down事件,则Down事件直接走到了ScrollView的OntouchEvent中

//DOWN事件就直接进入到了ScrollView的onTouchEvent
2021-04-05 20:44:24.339 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:44:24.339 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:44:24.339 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:44:24.355 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:44:24.356 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:44:24.357 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:44:24.373 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:44:24.374 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:44:24.375 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
2021-04-05 20:44:24.391 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_MOVE
2021-04-05 20:44:24.391 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_MOVE return:true
2021-04-05 20:44:24.391 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_MOVE return:true
// 因为ScorllView表示拦截了Down事件,上面MOVE事件也都直接给了ScrollView
2021-04-05 20:44:24.721 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent in :ACTION_UP
2021-04-05 20:44:24.722 8398-8398/com.plbear.leakcanary E/yanlog: scrollView onTouchEvent:ACTION_UP return:true
2021-04-05 20:44:24.722 8398-8398/com.plbear.leakcanary E/yanlog: scrollView dispatchTouchEvent:ACTION_UP return:true

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值