Android — 手撸代码学习事件分发的过程

前言 事件分发是一个困扰我已久的问题,今天终于鼓起勇气手撸代码来一探究竟,废话不多说,直接上代码。
首先,先粘出今天学习需要创建的类,Activity=>ViewGroup=>View
Android — 手撸代码学习事件分发的过程
文章图片

还是上代码吧
1.Activity

class DispatchEventActivity : AppCompatActivity(){ private val TAG: String = "study_DisActivity"override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_dispatchevent)}override fun dispatchTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(TAG, "Activity dispatchTouchEvent ACTION_DOWN") }MotionEvent.ACTION_MOVE -> { Log.d(TAG, "Activity dispatchTouchEvent ACTION_MOVE") }MotionEvent.ACTION_UP -> { Log.d(TAG, "Activity dispatchTouchEvent ACTION_UP") } } return super.dispatchTouchEvent(event) }override fun onTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(TAG, "Activity onTouchEvent ACTION_DOWN") }MotionEvent.ACTION_MOVE -> { Log.d(TAG, "Activity onTouchEvent ACTION_MOVE") }MotionEvent.ACTION_UP -> { Log.d(TAG, "Activity onTouchEvent ACTION_UP") } } return super.onTouchEvent(event) }}

2.View
class MyTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : TextView(context, attrs, defStyleAttr) {private val TAG: String = "study_My TextView"override fun dispatchTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(TAG, "View dispatchTouchEvent ACTION_DOWN") }MotionEvent.ACTION_MOVE -> { Log.d(TAG, "View dispatchTouchEvent ACTION_MOVE") }MotionEvent.ACTION_UP -> { Log.d(TAG, "View dispatchTouchEvent ACTION_UP") } } return super.dispatchTouchEvent(event) }override fun onTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(TAG, "View onTouchEvent ACTION_DOWN") }MotionEvent.ACTION_MOVE -> { Log.d(TAG, "View onTouchEvent ACTION_MOVE") }MotionEvent.ACTION_UP -> { Log.d(TAG, "View onTouchEvent ACTION_UP") } } return super.onTouchEvent(event) } }

3.ViewGroup
class MyLinearLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) {private val TAG: String = "study_ LinLayout"override fun onInterceptTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(TAG, "ViewGroup onInterceptTouchEvent ACTION_DOWN") }MotionEvent.ACTION_MOVE -> { Log.d(TAG, "ViewGroup onInterceptTouchEvent ACTION_MOVE") }MotionEvent.ACTION_UP -> { Log.d(TAG, "ViewGroup onInterceptTouchEvent ACTION_UP") } } return super.onInterceptTouchEvent(event) }override fun dispatchTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(TAG, "ViewGroup dispatchTouchEvent ACTION_DOWN") }MotionEvent.ACTION_MOVE -> { Log.d(TAG, "ViewGroup dispatchTouchEvent ACTION_MOVE") }MotionEvent.ACTION_UP -> { Log.d(TAG, "ViewGroup dispatchTouchEvent ACTION_UP") } } return super.dispatchTouchEvent(event) }override fun onTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(TAG, "ViewGroup onTouchEvent ACTION_DOWN") }MotionEvent.ACTION_MOVE -> { Log.d(TAG, "ViewGroup onTouchEvent ACTION_MOVE") }MotionEvent.ACTION_UP -> { Log.d(TAG, "ViewGroup onTouchEvent ACTION_UP") } } return super.onTouchEvent(event) }}

接下来看一下布局文件吧,白色部分为MyLinearLayout,灰色部分为MyTextView
Android — 手撸代码学习事件分发的过程
文章图片

接下来我们运行我们的代码,并点击屏幕测试,打印Log如下:
07-31 11:23:51.908 20729-20729/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_DOWN07-31 11:23:51.908 20729-20729/? D/study_LinLayout: ViewGroup dispatchTouchEvent ACTION_DOWN 07-31 11:23:51.908 20729-20729/? D/study_LinLayout: ViewGroup onInterceptTouchEvent ACTION_DOWN07-31 11:23:51.909 20729-20729/? D/study_My TextView: View dispatchTouchEvent ACTION_DOWN 07-31 11:23:51.909 20729-20729/? D/study_My TextView: View onTouchEvent ACTION_DOWN07-31 11:23:51.910 20729-20729/? D/study_LinLayout: ViewGroup onTouchEvent ACTION_DOWN07-31 11:23:51.912 20729-20729/? D/study_DisActivity: ActivityonTouchEvent ACTION_DOWN07-31 11:23:51.940 20729-20729/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_UP 07-31 11:23:51.940 20729-20729/? D/study_DisActivity: Activity onTouchEvent ACTION_UP

从日志我们分析出
Android — 手撸代码学习事件分发的过程
文章图片

从ACTION_DOWN 事件我们可以看出来,事件的分发过程确实是以 “U”型进行传递的。当然这一切都归于没有任何“人”消费事件的情况下。
假如我们对View设置一个onTouch事件并返回false【不消费事件】,我们设置好事件后重新执行代码,日志如下:
07-31 11:47:32.243 22295-22295/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_DOWN07-31 11:47:32.243 22295-22295/? D/study_LinLayout: ViewGroup dispatchTouchEvent ACTION_DOWN 07-31 11:47:32.244 22295-22295/? D/study_LinLayout: ViewGroup onInterceptTouchEvent ACTION_DOWN07-31 11:47:32.244 22295-22295/? D/study_My TextView: View dispatchTouchEvent ACTION_DOWN 07-31 11:47:32.244 22295-22295/? D/study_DisActivity: View onTouch ACTION_DOWN 07-31 11:47:32.245 22295-22295/? D/study_My TextView: View onTouchEvent ACTION_DOWN07-31 11:47:32.245 22295-22295/? D/study_LinLayout: ViewGroup onTouchEvent ACTION_DOWN 07-31 11:47:32.247 22295-22295/? D/study_DisActivity: Activity onTouchEvent ACTION_DOWN 07-31 11:47:32.286 22295-22295/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_UP 07-31 11:47:32.286 22295-22295/? D/study_DisActivity: Activity onTouchEvent ACTION_UP

这次我们看到onTouch 是优先于onTouchEvent 执行的,由此我们推测,如果onTouch返回true消费事件的话,那么View的onTouchEvent将不被执行,那么也就不会继续分发事件,接下来我们修改onTouch返回值为true,并查看日志:
07-31 11:52:03.698 22665-22665/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_DOWN 07-31 11:52:03.698 22665-22665/? D/study_LinLayout: ViewGroup dispatchTouchEvent ACTION_DOWN 07-31 11:52:03.698 22665-22665/? D/study_LinLayout: ViewGroup onInterceptTouchEvent ACTION_DOWN 07-31 11:52:03.698 22665-22665/? D/study_My TextView: View dispatchTouchEvent ACTION_DOWN 07-31 11:52:03.699 22665-22665/? D/study_DisActivity: View onTouch ACTION_DOWN07-31 11:52:03.738 22665-22665/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_UP 07-31 11:52:03.739 22665-22665/? D/study_LinLayout: ViewGroup dispatchTouchEvent ACTION_UP 07-31 11:52:03.739 22665-22665/? D/study_LinLayout: ViewGroup onInterceptTouchEvent ACTION_UP 07-31 11:52:03.739 22665-22665/? D/study_My TextView: View dispatchTouchEvent ACTION_UP 07-31 11:52:03.739 22665-22665/? D/study_DisActivity: View onTouch ACTION_UP

此处验证了我们的推测,ACTION_DOWN的事件到onTouch后被消费掉了,没有继续分发。我发现为何ACTION_UP事件如此奇怪,想了好久感觉可能是,当所有人都不消费事件时,就相当于处理权交给了Activity的onTouchEvent,所以ACTION_UP事件就分发到Activity的onTouchEvent结束,当我们把onTouch返回值改为true后,也就是onTouch要消费事件,那么ACTION_UP就会继续分发事件到onTouch里面。
如果View有onClick 事件会怎么样呢?我们还是修改代码看日志吧;
07-31 12:04:41.110 23525-23525/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_DOWN 07-31 12:04:41.110 23525-23525/? D/study_LinLayout: ViewGroup dispatchTouchEvent ACTION_DOWN 07-31 12:04:41.110 23525-23525/? D/study_LinLayout: ViewGroup onInterceptTouchEvent ACTION_DOWN 07-31 12:04:41.110 23525-23525/? D/study_My TextView: View dispatchTouchEvent ACTION_DOWN 07-31 12:04:41.110 23525-23525/? D/study_DisActivity: View onTouch ACTION_DOWN 07-31 12:04:41.111 23525-23525/? D/study_My TextView: View onTouchEvent ACTION_DOWN 07-31 12:04:41.142 23525-23525/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_UP 07-31 12:04:41.142 23525-23525/? D/study_LinLayout: ViewGroup dispatchTouchEvent ACTION_UP 07-31 12:04:41.142 23525-23525/? D/study_LinLayout: ViewGroup onInterceptTouchEvent ACTION_UP 07-31 12:04:41.142 23525-23525/? D/study_My TextView: View dispatchTouchEvent ACTION_UP 07-31 12:04:41.142 23525-23525/? D/study_DisActivity: View onTouch ACTION_UP 07-31 12:04:41.142 23525-23525/? D/study_My TextView: View onTouchEvent ACTION_UP07-31 12:04:41.143 23525-23525/? D/study_DisActivity:View onClick

我们发现如果View有onClick 方法,那么事件最终会被onClick 消费掉。
【Android — 手撸代码学习事件分发的过程】到此我们已经大致摸清了事件传递的过程,今天的学习就先到这里,有疑问的同学可以回复评论,咱们一起讨论学习,在此过程中提高我们自己。

    推荐阅读