Android 几句话总结事件分发

2021-09-23  本文已影响0人  雁过留声_泪落无痕

结论


  1. 事件分发遵循从上到下再从下到上的路径进行分发
Activity<=>ViewGroup<=>ViewGroup<=>...<=>ViewGroup<=>View
  1. Activity ViewGroup View 分别有以下方法
Activity#dispatchTouchEvent(MotionEvent ev)
Activity#onTouchEvent(MotionEvent ev)

ViewGroup#dispatchTouchEvent(MotionEvent ev)
ViewGroup#onInterceptTouchEvent(MotionEvent ev)
ViewGroup#onTouchEvent(MotionEvent ev)

View#dispatchTouchEvent(MotionEvent ev)
View#onTouchEvent(MotionEvent ev)
  1. 调用方法的路径为,整体呈一个 U 字形
Activity#dispatchTouchEvent(MotionEvent ev) -------- Activity#onTouchEvent(MotionEvent ev)
||                                                   /\
\/                                                   ||
ViewGroup#dispatchTouchEvent(MotionEvent ev)
||                                                   ||
\/                                                   ||
ViewGroup#onInterceptTouchEvent(MotionEvent ev) ---- ViewGroup#onTouchEvent(MotionEvent ev)
||                                                   /\
\/                                                   ||
View#dispatchTouchEvent(MotionEvent ev) ------------ View#onTouchEvent(MotionEvent ev)
||                                                   /\
||===================================================||

  1. 分发的事件包括
  • ACTION_DOWN
  • ACTION_MOVE
  • ACTION_UP
  • ACTION_CANCEL
  1. 谁处理了 ACTION_DOWN 事件,后续的事件就直接分发到谁
  1. 依然遵循从上到下,再从下到上,达到目标 View/ViewGroup 时停止
  2. 若 View 处理了 ACTION_DOWN 事件,后续事件从上到下并到该 View 的:
 View#dispatchTouchEvent(MotionEvent ev) => View#onTouchEvent(MotionEvent ev)
  1. 若 ViewGroup 处理了 ACTION_DOWN 事件,后续事件从上到下并到该 ViewGroup 的(不再走 onInterceptTouchEvent):
 ViewGroup#dispatchTouchEvent(MotionEvent ev) => ViewGroup#onTouchEvent(MotionEvent ev)
  1. 后续事件(ACTION_DOWN 后的第一个 ACTION_MOVE 或者从中间的某个 ACTION_MOVE 开始拦截效果都一样)被上层拦截(某 ViewGroup#onInterceptTouchEvent(MotionEvent ev) 返回 true),则当前事件转换成 ACTION_CANCEL 并传递到本应该(若不拦截的话)处理该事件的 View/ViewGroupdispatchTouchEvent(MotionEvent ev) => View/ViewGroup#onTouchEvent(MotionEvent ev),且后续事件都从上到下并到做了拦截处理的 ViewGroup 的(不论 onTouchEvent 返回值是 true 还是 false,除非再次被更上层的 ViewGroup 拦截):
 ViewGroup#dispatchTouchEvent(MotionEvent ev) => ViewGroup#onTouchEvent(MotionEvent ev)
  1. 无人处理 ACTION_DOWN 事件,则后续事件不再走 ViewGroup 和 View,只到 Activity 的:
Activity#dispatchTouchEvent(MotionEvent ev) => Activity#onTouchEvent(MotionEvent ev)

测试代码


class TestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val groupA = MyViewGroupA(this)
        val groupB = MyViewGroupB(this)
        val view = MyView(this)
        groupB.addView(view)
        groupA.addView(groupB)
        setContentView(groupA)
    }

}

fun getAction(ev: MotionEvent): String {
    var result = ""
    when (ev.action) {
        MotionEvent.ACTION_DOWN -> result = "down"
        MotionEvent.ACTION_MOVE -> result = "move"
        MotionEvent.ACTION_UP -> result = "up"
        MotionEvent.ACTION_CANCEL -> result = "cancel"
    }

    return "$result, ${ev.eventTime}"
}

class MyViewGroupA(context: Context) : FrameLayout(context) {

    var count = 0

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyViewGroupA#dispatchTouchEvent(), ev: ${getAction(ev)}")
        return super.dispatchTouchEvent(ev)
    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyViewGroupA#onInterceptTouchEvent(), ev: ${getAction(ev)}")
        if (count++ >= 3 && ev.action == MotionEvent.ACTION_MOVE) {
            return true
        }

        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyViewGroupA#onTouchEvent(), ev: ${getAction(ev)}")
        return super.onTouchEvent(ev)
    }

}

class MyViewGroupB(context: Context) : FrameLayout(context) {

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyViewGroupB#dispatchTouchEvent(), ev: ${getAction(ev)}")
        return super.dispatchTouchEvent(ev)
    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyViewGroupB#onInterceptTouchEvent(), ev: ${getAction(ev)}")
        if (ev.action == MotionEvent.ACTION_MOVE) {
            return true
        }

        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyViewGroupB#onTouchEvent(), ev: ${getAction(ev)}")
        return super.onTouchEvent(ev)
    }

}

class MyView(context: Context) : View(context) {

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyView#dispatchTouchEvent(), ev: ${getAction(ev)}")
        return super.dispatchTouchEvent(ev)
    }

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        Log.d("hehe", "MyView#onTouchEvent(), ev: ${getAction(ev)}")
        if (ev.action == MotionEvent.ACTION_DOWN) {
            return true
        }

        return super.onTouchEvent(ev)
    }

}

日志:


# 首次 DOWN 事件到了 View
MyViewGroupA#dispatchTouchEvent(), ev: down, 756200913
MyViewGroupA#onInterceptTouchEvent(), ev: down, 756200913
MyViewGroupB#dispatchTouchEvent(), ev: down, 756200913
MyViewGroupB#onInterceptTouchEvent(), ev: down, 756200913
MyView#dispatchTouchEvent(), ev: down, 756200913
MyView#onTouchEvent(), ev: down, 756200913

# 接下来的第一次 MOVE 事件被 MyViewGroupB 拦截
MyViewGroupA#dispatchTouchEvent(), ev: move, 756200930
MyViewGroupA#onInterceptTouchEvent(), ev: move, 756200930
MyViewGroupB#dispatchTouchEvent(), ev: move, 756200930
MyViewGroupB#onInterceptTouchEvent(), ev: move, 756200930
MyView#dispatchTouchEvent(), ev: cancel, 756200930
MyView#onTouchEvent(), ev: cancel, 756200930

# 紧接着的第二次 MOVE 事件正常到 MyViewGroupB
MyViewGroupA#dispatchTouchEvent(), ev: move, 756200940
MyViewGroupA#onInterceptTouchEvent(), ev: move, 756200940
MyViewGroupB#dispatchTouchEvent(), ev: move, 756200940
MyViewGroupB#onTouchEvent(), ev: move, 756200940

# 再下来的第三次 MOVE 事件被 MyViewGroupA 拦截
MyViewGroupA#dispatchTouchEvent(), ev: move, 756200950
MyViewGroupA#onInterceptTouchEvent(), ev: move, 756200950
MyViewGroupB#dispatchTouchEvent(), ev: cancel, 756200950
MyViewGroupB#onTouchEvent(), ev: cancel, 756200950

# 以后的事件都直接到 MyViewGroupA 了
MyViewGroupA#dispatchTouchEvent(), ev: move, 756200959
MyViewGroupA#onTouchEvent(), ev: move, 756200959

MyViewGroupA#dispatchTouchEvent(), ev: move, 756200970
MyViewGroupA#onTouchEvent(), ev: move, 756200970

MyViewGroupA#dispatchTouchEvent(), ev: move, 756201105
MyViewGroupA#onTouchEvent(), ev: move, 756201105

MyViewGroupA#dispatchTouchEvent(), ev: up, 756201113
MyViewGroupA#onTouchEvent(), ev: up, 756201113
上一篇下一篇

猜你喜欢

热点阅读