美文网首页
Android 几句话总结事件分发

Android 几句话总结事件分发

作者: 雁过留声_泪落无痕 | 来源:发表于2021-09-23 10:22 被阅读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
    

    相关文章

      网友评论

          本文标题:Android 几句话总结事件分发

          本文链接:https://www.haomeiwen.com/subject/zrmngltx.html