【Android】事件分发

【笔记】【Android】事件分发

简述

 在Android开发中会遇到多个View、ViewGroup嵌套的情景,例如ViewPager中嵌套Fragment,同时在Fragment内嵌套一个可滚动的RecyclerView,就会出现ViewPager和RecyclerView的滑动事件就会冲突,这时候就需要处理触摸事件。

 一次完整的事件传递分为三个阶段,分别是事件的分发、拦截和消费。

触摸事件和类型

触摸时间对应的是MotionEvent类, 事件的类型主要有三种:
– ACTION_DOWN: 用户的按下操作, 一个按下操作标志着一次触摸时间的开始。
– ACTION_MOVE: 用户按下后松开前, 如果移动的距离超过阈值, 则判定为ACTION_MOVE操作。
– ACTION_UP: 用户抬起操作, 一个抬起操作标志着一次触摸事件的结束。

在一次屏幕触摸操作中,ACTION_DOWN和ACTION_UP这两个事件是必需的, 而ACTION_MOVE需移动触发。

事件传递的三个阶段

  • 分发(Dispatch): 事件的分发对应dispatchTouchEvent方法 , 在Android中 , 所有的触摸事件都是通过这个方法分发的:
override fun dispatchTouchEvent(event: MotionEvent?): Boolean

在这个方法中国,根据实际的实现逻辑来决定这个事件是否继续分发给子视图处理。当方法返回true时, 表示该事件被消费, 不再分发; 方法返回super.dispatchTouchEvent则表示继续分发事件。如果当前视图是ViewGroup及其子类, 则会调用onInterceptTouchEvent判定是否拦截该事件。

  • 拦截(Intercept) : 事件的拦截对应着onInterceptTouchEvent, 这个方法仅在ViewGroup及其子类存在, 在ViewActivity中不存在。
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean

同理, 此方法也是通过返回值来决定是否拦截事件 , 当返回true时, 表示拦截事件, 不继续分发给子视图, 同时交由自身的onTouchEvent方法进行消费。

  • 消费(Consume) : 事件的消费对应OnTouchEvent方法:
override fun onTouchEvent(event: MotionEvent?): Boolean

此方法返回true表示当前View可以处理消费对应的事件 , 事件将不会向上传递给父View; 返回false表示不消费事件, 事件会向上传递给俯视图的OnTouchEvent方法。

拥有事件传递处理能力的类有三个:
– Avtivity: dispatchTouchEventonTouchEvent
– ViewGroup : dispatchTouchEventonInterceptTouchEventonTouchEvent
– View : dispatchTouchEventonTouchEvent

View的事件传递机制

我们首先定义一个继承TextView的类MyTextView (不继承ViewGroup及其子类)。

class MyTextView : TextView {
    private val TAG="binbinMyTextView"

    …………

    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        var actionStr=""
        when (event?.action){
            MotionEvent.ACTION_DOWN ->{
                actionStr="ACTION_DOWN"
            }
            MotionEvent.ACTION_UP ->{
                actionStr="ACTION_UP"
            }
            MotionEvent.ACTION_MOVE ->{
                actionStr="ACTION_MOVE"
            }
            MotionEvent.ACTION_CANCEL->{
                actionStr="ACTION_CANCEL"
            }
            else ->{
                actionStr="else"
            }
        }
        e(TAG,"dispatchTouchEvent $actionStr")
        return super.dispatchTouchEvent(event)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        var actionStr=""
        when (event?.action){
            MotionEvent.ACTION_DOWN ->{
                actionStr="ACTION_DOWN"
            }
            MotionEvent.ACTION_UP ->{
                actionStr="ACTION_UP"
            }
            MotionEvent.ACTION_MOVE ->{
                actionStr="ACTION_MOVE"
            }
            MotionEvent.ACTION_CANCEL->{
                actionStr="ACTION_CANCEL"
            }
            else ->{
                actionStr="else"
            }
        }
        e(TAG,"onTouchEvent   $actionStr")
        return super.onTouchEvent(event)
    }

}

然后再定义一个Activity展示MyTextView并设置点击和触摸监听。

class MainActivity : AppCompatActivity() ,View.OnTouchListener,View.OnClickListener{
    private val TAG="binbinMainActivity"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<MyTextView>(R.id.myTextView).setOnClickListener(this)
        findViewById<MyTextView>(R.id.myTextView).setOnTouchListener(this)
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        var actionStr=""
        when (ev?.action){
            MotionEvent.ACTION_DOWN ->{
                actionStr="ACTION_DOWN"
            }
            MotionEvent.ACTION_UP ->{
                actionStr="ACTION_UP"
            }
            MotionEvent.ACTION_MOVE ->{
                actionStr="ACTION_MOVE"
            }
            MotionEvent.ACTION_CANCEL->{
                actionStr="ACTION_CANCEL"
            }
            else ->{
                actionStr="else"
            }
        }
        e(TAG,"dispatchTouchEvent  $actionStr")
        return super.dispatchTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        var actionStr=""
        when (event?.action){
            MotionEvent.ACTION_DOWN ->{
                actionStr="ACTION_DOWN"
            }
            MotionEvent.ACTION_UP ->{
                actionStr="ACTION_UP"
            }
            MotionEvent.ACTION_MOVE ->{
                actionStr="ACTION_MOVE"
            }
            MotionEvent.ACTION_CANCEL->{
                actionStr="ACTION_CANCEL"
            }
            else ->{
                actionStr="else"
            }
        }
        e(TAG,"onTouchEvent  $actionStr")
        return super.onTouchEvent(event)
    }

    override fun onTouch(v: View?, event: MotionEvent?): Boolean {
        when(v?.id){
            R.id.myTextView ->{
                var actionStr=""
                when (event?.action){
                    MotionEvent.ACTION_DOWN ->{
                        actionStr="ACTION_DOWN"
                    }
                    MotionEvent.ACTION_UP ->{
                        actionStr="ACTION_UP"
                    }
                    MotionEvent.ACTION_MOVE ->{
                        actionStr="ACTION_MOVE"
                    }
                    MotionEvent.ACTION_CANCEL->{
                        actionStr="ACTION_CANCEL"
                    }
                    else ->{
                        actionStr="else"
                    }
                }
                e(TAG,"onTouch  $actionStr")
            }
        }
        return super.onTouchEvent(event)
    }

    override fun onClick(v: View?) {
        when(v?.id){
            R.id.myTextView ->{
                e(TAG,"onClick")
            }
        }
    }

}

运行代码, 点击MyTextView, 得到如下日志:

com.bin.toucheventtest E/binbinMainActivity: dispatchTouchEvent  ACTION_DOWN
com.bin.toucheventtest E/binbinMyTextView: dispatchTouchEvent ACTION_DOWN
com.bin.toucheventtest E/binbinMainActivity: onTouch  ACTION_DOWN
com.bin.toucheventtest E/binbinMyTextView: onTouchEvent   ACTION_DOWN
com.bin.toucheventtest E/binbinMainActivity: dispatchTouchEvent  ACTION_UP
com.bin.toucheventtest E/binbinMyTextView: dispatchTouchEvent ACTION_UP
com.bin.toucheventtest E/binbinMainActivity: onTouch  ACTION_UP
com.bin.toucheventtest E/binbinMyTextView: onTouchEvent   ACTION_UP
com.bin.toucheventtest E/binbinMainActivity: onClick

从上面的代码看出, dispatchTouchEvent、onTouchEvent两个方法返回值有三种情况:
– false
– true
– super.同名方法

不同的返回值使事件传递流程走向不同。

ACTION_DOWN事件的处理流程如图:

图片描述

未完待续

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇