Android(安卓)— 手撸代码学习事件分发的过程
前言
事件分发是一个困扰我已久的问题,今天终于鼓起勇气手撸代码来一探究竟,废话不多说,直接上代码。
首先,先粘出今天学习需要创建的类,Activity => ViewGroup => View
还是上代码吧
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
接下来我们运行我们的代码,并点击屏幕测试,打印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_DOWN07-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_DOWN07-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: Activity onTouchEvent ACTION_DOWN07-31 11:23:51.940 20729-20729/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_UP07-31 11:23:51.940 20729-20729/? D/study_DisActivity: Activity onTouchEvent ACTION_UP
从日志我们分析出
从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_DOWN07-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_DOWN07-31 11:47:32.244 22295-22295/? D/study_DisActivity: View onTouch ACTION_DOWN07-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_DOWN07-31 11:47:32.247 22295-22295/? D/study_DisActivity: Activity onTouchEvent ACTION_DOWN07-31 11:47:32.286 22295-22295/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_UP07-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_DOWN07-31 11:52:03.698 22665-22665/? D/study_ LinLayout: ViewGroup dispatchTouchEvent ACTION_DOWN07-31 11:52:03.698 22665-22665/? D/study_ LinLayout: ViewGroup onInterceptTouchEvent ACTION_DOWN07-31 11:52:03.698 22665-22665/? D/study_My TextView: View dispatchTouchEvent ACTION_DOWN07-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_UP07-31 11:52:03.739 22665-22665/? D/study_ LinLayout: ViewGroup dispatchTouchEvent ACTION_UP07-31 11:52:03.739 22665-22665/? D/study_ LinLayout: ViewGroup onInterceptTouchEvent ACTION_UP07-31 11:52:03.739 22665-22665/? D/study_My TextView: View dispatchTouchEvent ACTION_UP07-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_DOWN07-31 12:04:41.110 23525-23525/? D/study_ LinLayout: ViewGroup dispatchTouchEvent ACTION_DOWN07-31 12:04:41.110 23525-23525/? D/study_ LinLayout: ViewGroup onInterceptTouchEvent ACTION_DOWN07-31 12:04:41.110 23525-23525/? D/study_My TextView: View dispatchTouchEvent ACTION_DOWN07-31 12:04:41.110 23525-23525/? D/study_DisActivity: View onTouch ACTION_DOWN07-31 12:04:41.111 23525-23525/? D/study_My TextView: View onTouchEvent ACTION_DOWN07-31 12:04:41.142 23525-23525/? D/study_DisActivity: Activity dispatchTouchEvent ACTION_UP07-31 12:04:41.142 23525-23525/? D/study_ LinLayout: ViewGroup dispatchTouchEvent ACTION_UP07-31 12:04:41.142 23525-23525/? D/study_ LinLayout: ViewGroup onInterceptTouchEvent ACTION_UP07-31 12:04:41.142 23525-23525/? D/study_My TextView: View dispatchTouchEvent ACTION_UP07-31 12:04:41.142 23525-23525/? D/study_DisActivity: View onTouch ACTION_UP07-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中屏幕触摸事件
- android_8.1 hdmi设备热插拔事件
- Android之屏幕方向改变以及onConfigurationChanged事件
- Android7 InputReader InputDispatcher Key Touch
- Android(安卓)ListView setOnItemClickListener/setOnItemSelect
- Android(安卓)连续多次点击事件的实现
- android中view手势滑动冲突的解决方法
- Android(安卓)笔记5---事件处理和手势
- Android之广播大全 Intent Action 事件