zoukankan      html  css  js  c++  java
  • 理解Android View的事件传递机制

    在android事件传递一般包括三个对象: Activity,ViewGroup,View,事件分发顺序为:Activity->ViewGroup->View,事件分发过程由

    onTouchEvent()
    onInterceptTouchEvent()
    dispatchTouchEvent()

    这三个方法协助完成, 其中View没有onInterceptTouchEvent()方法

    下面用一个简单的例子进行说明:

    testButton, testLayout为自定义控件

    class MainActivity : AppCompatActivity(), View.OnTouchListener {
     override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    //view没有onInterceptTouchEvent
    //onTouch事件优于onClick
    btnTest.setOnTouchListener(this)
    btnTest.setOnClickListener {
    Toast.makeText(this@MainActivity,"te", Toast.LENGTH_LONG).show()
    }
    }

    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
    when (v){
    mainLayout->{
    when (event?.action){
    MotionEvent.ACTION_DOWN->{
    Log.d("touch event","mainLayout ACTION_DOWN")
    }
    MotionEvent.ACTION_UP->{
    Log.d("touch event","mainLayout ACTION_UP")
    }
    }
    }
    btnTest->{
    when (event?.action){
    MotionEvent.ACTION_DOWN->{
    Log.d("touch event","btnTest ACTION_DOWN")
    }
    MotionEvent.ACTION_UP->{
    Log.d("touch event","btnTest ACTION_UP")
    }
    }
    }
    }
    return true
    }

    //activity的dispatchTouchEvent
    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
    //事件分派
    when (ev?.action){
    MotionEvent.ACTION_DOWN->{
    Log.d("touch event","activity dispatchTouchEvent ACTION_DOWN")
    //在ACTION_DOWN return true,子view收不到后面的事件
    //return true
    }
    MotionEvent.ACTION_UP->{
    Log.d("touch event","activity dispatchTouchEvent ACTION_UP")
    //ACTION_UP return true,子view收不到ACTION_UP
    //return true
    }
    }
    return super.dispatchTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
    return super.onTouchEvent(event)
    }

    }
    class TestButton:Button {
    
        constructor(mContext: Context) : super(mContext) {
            val context = mContext
        }
        constructor(mContext: Context, mAttributeSet: AttributeSet) : super(mContext, mAttributeSet) {
            val context = mContext
        }
    
        override fun onTouchEvent(event: MotionEvent?): Boolean {
            //return super.onTouchEvent(event)
            when (event?.action){
                MotionEvent.ACTION_DOWN->{
                    Log.d("touch event","btnTest ACTION_DOWN")
                    return true
                }
                MotionEvent.ACTION_UP->{
                    Log.d("touch event","btnTest ACTION_UP")
                }
            }
            //如果返回true,不会把onTouch事件传递回activity,就是说activity的onTouchEvent不会被调用
              return true
        }
    
        override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
            return super.dispatchTouchEvent(event)
        }
    
    }
    

      

    class TestLayout : ConstraintLayout{
    
        constructor(mContext: Context) : super(mContext) {
            val context = mContext
        }
        constructor(mContext: Context, mAttributeSet: AttributeSet) : super(mContext, mAttributeSet) {
            val context = mContext
        }
    
        override fun onTouchEvent(event: MotionEvent?): Boolean {
            //return super.onTouchEvent(event)
            Log.d("touch event","view group")
            return true
        }
    
        override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
            //return super.onInterceptTouchEvent(ev)
            //true:中断事件
            //中断后, TestLayout的子view btnTest的onTouch,onClick都不会执行
            return true
        }
    
        override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
            //事件分派
            when (ev?.action){
                MotionEvent.ACTION_DOWN->{
                    Log.d("touch event","view group dispatchTouchEvent ACTION_DOWN")
                    //在ACTION_DOWN return true,子view收不到后面的事件
                    //return true
                }
                MotionEvent.ACTION_UP->{
                    Log.d("touch event","view group dispatchTouchEvent ACTION_UP")
                    //ACTION_UP return true,子view收不到ACTION_UP
                    //return true
                }
            }
            return super.dispatchTouchEvent(ev)
        }
    }
    

     

    我们通过log查看到,每次touch btnTest或mainLayout,都会先打印Activity里的dispatchTouchEvent里的ACTION_DOWN,是传递的起点

    a. 如果Activity的dispatchTouchEvent里的ACTION_DOWN return true,子view就收不到事件传递了;

    b. TestLayout的onInterceptTouchEvent,如果return true,表示中断传递给子view的事件,TestButton的onTouch,onClick都不会执行,会走TestLayout的onTouchEvent;就是说如果ViewGroup的onInterceptTouchEvent return true,就会走自已的onTouchEvent();

    c. 如果TestLayout的onTouchEvent return true,就是消费掉事件,不会把onTouch事件传递回activity,就是说activity的onTouchEvent不会被调用

    d. 同理TestButton的onTouchEvent return true,也不会把onTouch事件传递回activity,就是说activity的onTouchEvent不会被调用

     

    如果view,viewgroup都没有对事件进行消费,会以activity的onTouchEvent作为终点;

    如果viewgroup中断事件并对事件进行消费,会以viewgroup onTouchEvent作为终点;

    如果viewgroup没有中断事件,但view(如button)对事件进行消费,会以button ACTION_UP作为终点;

    如果viewgroup没有中断事件,view也没有对事件进行消费,会以activity的onTouchEvent作为终点;



  • 相关阅读:
    客户端通过spice-gtk实现USB重定向
    KVM通过qemu实现USB重定向
    Json
    《卓有成效的管理者》读书笔记
    《第五项修炼•实践篇》读书笔记
    《远大前程——从软件新手到行业大件》读书笔记
    目前常用的网站
    Objective-C内存管理
    Ubuntu修改屏幕默认亮度
    Ubuntu下安装eclipse及PyDev插件注意事项
  • 原文地址:https://www.cnblogs.com/johnnyzhao/p/10350809.html
Copyright © 2011-2022 走看看