Android事件传递机制

180 阅读3分钟

Android 事件传递机制

本文从实践中观察事件是如何传递的。直接上代码观察。

1. 自定义View

MotionEventActivity

package edu.tyut.helloworld

import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.app.AppCompatActivity
import edu.tyut.helloworld.databinding.ActivityMotionEventBinding

private const val TAG: String = "MotionEventActivity"

class MotionEventActivity : AppCompatActivity() {

    private val binding: ActivityMotionEventBinding by lazy {
        ActivityMotionEventBinding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        initView()
    }
    private fun initView(){
        Log.i(TAG, "initView...")
    }

    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
                Log.i(TAG, "dispatchTouchEvent -> action down...")
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "dispatchTouchEvent -> action move...")
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "dispatchTouchEvent -> action up...")
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.i(TAG, "dispatchTouchEvent -> action cancel...")
            }
            else -> {
                Log.i(TAG, "dispatchTouchEvent -> else...")
            }
        }
        return super.dispatchTouchEvent(event).apply {
            Log.i(TAG, "dispatchTouchEvent -> isConsume: $this")
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
                Log.i(TAG, "onTouchEvent -> action down...")
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "onTouchEvent -> action move...")
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "onTouchEvent -> action up...")
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.i(TAG, "onTouchEvent -> action cancel...")
            }
            else -> {
                Log.i(TAG, "onTouchEvent -> else...")
            }
        }
        return super.onTouchEvent(event).apply {
            Log.i(TAG, "onTouchEvent -> isConsume: $this")
        }
    }
}

layout/activity_motion_event.xml

<?xml version="1.0" encoding="utf-8"?>
<edu.tyut.helloworld.view.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <edu.tyut.helloworld.view.CustomView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</edu.tyut.helloworld.view.CustomLinearLayout>

CustomLinearLayout

package edu.tyut.helloworld.view

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.widget.LinearLayoutCompat

private const val TAG: String = "CustomLinearLayout"

class CustomLinearLayout : LinearLayoutCompat {
    constructor(context: Context) : this(context = context, attributeSet = null)
    constructor(context: Context, attributeSet: AttributeSet?) : this(context = context, attributeSet = attributeSet, defStyleAttr = 0)
    constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr){
        initView()
    }
    private fun initView(){
        Log.i(TAG, "initView...")
    }
    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
                Log.i(TAG, "dispatchTouchEvent -> action down...")
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "dispatchTouchEvent -> action move...")
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "dispatchTouchEvent -> action up...")
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.i(TAG, "dispatchTouchEvent -> action cancel...")
            }
            else -> {
                Log.i(TAG, "dispatchTouchEvent -> else...")
            }
        }
        return super.dispatchTouchEvent(event).apply {
            Log.i(TAG, "dispatchTouchEvent -> isConsume: $this")
        }
    }

    override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
                performClick()
                Log.i(TAG, "onInterceptTouchEvent -> action down...")
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "onInterceptTouchEvent -> action move...")
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "onInterceptTouchEvent -> action up...")
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.i(TAG, "onInterceptTouchEvent -> action cancel...")
            }
            else -> {
                Log.i(TAG, "onInterceptTouchEvent -> else...")
            }
        }
        return super.onInterceptTouchEvent(event).apply {
            Log.i(TAG, "onInterceptTouchEvent -> isConsume: $this")
        }
    }

    override fun performClick(): Boolean {
        return super.performClick().apply {
            Log.i(TAG, "performClick -> isConsume: $this")
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
                performClick()
                Log.i(TAG, "onTouchEvent -> action down...")
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "onTouchEvent -> action move...")
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "onTouchEvent -> action up...")
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.i(TAG, "onTouchEvent -> action cancel...")
            }
            else -> {
                Log.i(TAG, "onTouchEvent -> else...")
            }
        }
        return super.onTouchEvent(event).apply {
            Log.i(TAG, "onTouchEvent -> isConsume: $this")
        }
    }

}

CustomView

package edu.tyut.helloworld.view

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

private const val TAG: String = "CustomView"

class CustomView : View {
    constructor(context: Context) : this(context = context, attributeSet = null)
    constructor(context: Context, attributeSet: AttributeSet?) : this(context = context, attributeSet = attributeSet, defStyleAttr = 0)
    constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr){
        initView()
    }
    private fun initView(){
        Log.i(TAG, "initView...")
    }

    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
                Log.i(TAG, "dispatchTouchEvent -> action down...")
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "dispatchTouchEvent -> action move...")
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "dispatchTouchEvent -> action up...")
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.i(TAG, "dispatchTouchEvent -> action cancel...")
            }
            else -> {
                Log.i(TAG, "dispatchTouchEvent -> else...")
            }
        }
        return super.dispatchTouchEvent(event).apply {
            Log.i(TAG, "dispatchTouchEvent -> isConsume: $this")
        }
    }

    override fun performClick(): Boolean {
        return super.performClick().apply {
            Log.i(TAG, "performClick -> isConsume: $this")
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {
                performClick()
                Log.i(TAG, "onTouchEvent -> action down...")
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "onTouchEvent -> action move...")
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "onTouchEvent -> action up...")
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.i(TAG, "onTouchEvent -> action cancel...")
            }
            else -> {
                Log.i(TAG, "onTouchEvent -> else...")
            }
        }
        return super.onTouchEvent(event).apply {
            Log.i(TAG, "onTouchEvent -> isConsume: $this")
        }
    }
}

分析日志

点击手机屏幕,日志如下:

2025-03-03 14:15:09.808 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  dispatchTouchEvent -> action down...
2025-03-03 14:15:09.809 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  dispatchTouchEvent -> action down...
2025-03-03 14:15:09.810 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  performClick -> isConsume: false
2025-03-03 14:15:09.810 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  onInterceptTouchEvent -> action down...
2025-03-03 14:15:09.810 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  onInterceptTouchEvent -> isConsume: false
2025-03-03 14:15:09.810 23938-23938 CustomView              edu.tyut.helloworld                  I  dispatchTouchEvent -> action down...
2025-03-03 14:15:09.810 23938-23938 CustomView              edu.tyut.helloworld                  I  performClick -> isConsume: false
2025-03-03 14:15:09.810 23938-23938 CustomView              edu.tyut.helloworld                  I  onTouchEvent -> action down...
2025-03-03 14:15:09.810 23938-23938 CustomView              edu.tyut.helloworld                  I  onTouchEvent -> isConsume: false
2025-03-03 14:15:09.810 23938-23938 CustomView              edu.tyut.helloworld                  I  dispatchTouchEvent -> isConsume: false
2025-03-03 14:15:09.810 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  performClick -> isConsume: false
2025-03-03 14:15:09.810 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  onTouchEvent -> action down...
2025-03-03 14:15:09.810 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  onTouchEvent -> isConsume: false
2025-03-03 14:15:09.810 23938-23938 CustomLinearLayout      edu.tyut.helloworld                  I  dispatchTouchEvent -> isConsume: false
2025-03-03 14:15:09.811 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  onTouchEvent -> action down...
2025-03-03 14:15:09.811 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  onTouchEvent -> isConsume: false
2025-03-03 14:15:09.811 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  dispatchTouchEvent -> isConsume: false
2025-03-03 14:15:09.812 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  dispatchTouchEvent -> action up...
2025-03-03 14:15:09.813 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  onTouchEvent -> action up...
2025-03-03 14:15:09.813 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  onTouchEvent -> isConsume: false
2025-03-03 14:15:09.813 23938-23938 MotionEventActivity     edu.tyut.helloworld                  I  dispatchTouchEvent -> isConsume: false

其事件传递图为:

image.png