目录
假设有这么一道题目,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