Android面试老生常谈的 View 事件分发机制,看这一篇就够了!

override fun onTouch(v: View, event: MotionEvent): Boolean {

if (event.action == MotionEvent.ACTION_DOWN) {

clickCount++

handler.postDelayed({

if (clickCount == 1) {

myClickCallBack.oneClick()

} else if (clickCount == 2) {

myClickCallBack.doubleClick()

}

handler.removeCallbacksAndMessages(null)

//清空handler延时,并防内存泄漏

clickCount = 0 //计数清零

}, timeout.toLong()) //延时timeout后执行run方法中的代码

}

return false //让点击事件继续传播,方便再给View添加其他事件监听

}

companion object {

private const val TAG = “MyClickListener”

private val timeout = ViewConfiguration.getDoubleTapTimeout() //双击间四百毫秒延时

init {

Log.i(TAG, "timeout is $timeout ")

}

}

}

三击事件


三级事件呢,其实也很简单,我们直接判断在指定时间间隔内点击的次数即可

open class MyMultiTouchListener(private val myClickCallBack: MyClickCallBack) : OnTouchListener {

private var clickCount = 0 //记录连续点击次数

private val handler: Handler = Handler()

interface MyClickCallBack {

fun oneClick() //点击一次的回调

fun doubleClick() //连续点击两次的回调

fun threeClick() // 连续点击三次的回调

}

override fun onTouch(v: View, event: MotionEvent): Boolean {

if (event.action == MotionEvent.ACTION_DOWN) {

clickCount++

handler.postDelayed({

if (clickCount == 1) {

myClickCallBack.oneClick()

} else if (clickCount == 2) {

myClickCallBack.doubleClick()

} else if (clickCount == 3) {

myClickCallBack.threeClick()

}

handler.removeCallbacksAndMessages(null)

//清空handler延时,并防内存泄漏

clickCount = 0 //计数清零

}, timeout.toLong()) //延时timeout后执行run方法中的代码

}

return false //让点击事件继续传播,方便再给View添加其他事件监听

}

companion object {

private const val TAG = “MyClickListener”

private val timeout = 600 //双击间四百毫秒延时

init {

Log.i(TAG, "timeout is $timeout ")

}

}

}


手势识别

==================================================================

在 Android 开发当中,几乎所有的事件都会与用户进行交互,而我们用得的最多的就是手势了。

我们知道当我们触摸屏幕的时候,会产生很多事件,比如 down,move,up, fling 事件等等。一些简单的处理,我们可以直接重写 View 的 onTouchEvent 方法,根据 View 的 MotionEvent 事件进行处理。

而 Google 为了方便开发者方便接入,提供了几个默认处理类,那就是 GestureDetector 和 ScaleGestureDetector。

GestureDetector这个类对外提供了两个接口和一个外部类 。 接口:OnGestureListener,OnDoubleTapListener

内部类:SimpleOnGestureListener,同时实现了 OnGestureListener,OnDoubleTapListener 接口,如果只想使用接口里面的某个方法,可以直接使用它,方便快捷。

讲解之前,我们向来看一下怎么使用

GestureDetector(Context context, GestureDetector.OnGestureListener listener)

GestureDetector 基本使用


第一步,初始化 GestureDetector 对象

mDetector = GestureDetectorCompat(this, MyGestureListener())

可以看到有两个参数,第一个参数 context,第二个参数 OnGestureListener,我们可以直接实现 OnGestureListener 接口,也可以直接使用 GestureDetector.SimpleOnGestureListener

private class MyGestureListener : GestureDetector.OnGestureListener {

private val TAG = “GestureDemoActivity”

override fun onShowPress(e: MotionEvent?) {

Log.d(TAG, “onShowPress: e is $e”)

}

override fun onSingleTapUp(e: MotionEvent?): Boolean {

Log.d(TAG, “onSingleTapUp: e is $e”)

return false

}

override fun onDown(event: MotionEvent): Boolean {

Log.d(TAG, “onDown: $event”)

return true

}

override fun onFling(

event1: MotionEvent,

event2: MotionEvent,

velocityX: Float,

velocityY: Float

): Boolean {

Log.d(TAG, “onFling: $event1 $event2”)

return false

}

override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {

Log.d(TAG, "onScroll: distanceX is $distanceX,distanceY is $distanceY ")

return false

}

override fun onLongPress(e: MotionEvent?) {

Log.d(TAG, “onLongPress: e is $e”)

}

}

第二步:设置双击监听

// 设置双击监听

mDetector.setOnDoubleTapListener(object : GestureDetector.OnDoubleTapListener {

override fun onDoubleTap(e: MotionEvent?): Boolean {

Log.d(TAG, “onDoubleTap: e is e”)

return false

}

override fun onDoubleTapEvent(e: MotionEvent?): Boolean {

Log.d(TAG, “onDoubleTapEvent: e is e”)

return false

}

override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {

Log.d(TAG, “onSingleTapConfirmed: e is e”)

return false

}

})

最后,重写 Activity 或者 View 的 onTouchEvent ,将事件交给 mDetector 处理。

通常会有两种写法,第一种是如果手势处理器处理了,直接返回 true,进行消费。否则,进行默认处理

override fun onTouchEvent(event: MotionEvent): Boolean {

return if (mDetector.onTouchEvent(event)) {

true

} else {

super.onTouchEvent(event)

}

}

第二种写法是直接在 onTouchEvent 方法中,直接调用 mDetector.onTouchEvent(event) 方法

override fun onTouchEvent(event: MotionEvent): Boolean {

mDetector.onTouchEvent(event)

return super.onTouchEvent(event)

}

第二种写法,一般不会影响当前 View 或者 Activity 事件的传递,在开发当中,有时候为了减少一些触摸事件的冲突,经常这样写。

ScaleGestureDetector 这里暂时不展开描述了了,写着写着,发现好多呀,一个周末就这样过去,贼快,觉得对你有帮助的,请来个三连,点赞,收藏,转发😆


小结

================================================================

这篇文章,其实不难。主要是将 View 的事件分发机制,滑动冲突,以及开发当中经常用到的一些知识点,总结一下。

参考博客:

图解 Android 事件分发机制

ViewPager,ScrollView 嵌套ViewPager滑动冲突解决

Demo 地址

如果觉得对你有所帮助的话,可以关注我的微信公众号程序员徐公

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

最后

Android学习是一条漫长的道路,我们要学习的东西不仅仅只有表面的 技术,还要深入底层,弄明白下面的 原理,只有这样,我们才能够提高自己的竞争力,在当今这个竞争激烈的世界里立足。

人生不可能一帆风顺,有高峰自然有低谷,要相信,那些打不倒我们的,终将使我们更强大,要做自己的摆渡人。

我把自己这段时间整理的Android最重要最热门的学习方向资料放在了我的GitHub,里面还有不同方向的自学编程路线、面试题集合/面经、及系列技术文章等。

-e9ez8y0Q-1711378458578)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-4xhlBjmI-1711378458579)]

最后

Android学习是一条漫长的道路,我们要学习的东西不仅仅只有表面的 技术,还要深入底层,弄明白下面的 原理,只有这样,我们才能够提高自己的竞争力,在当今这个竞争激烈的世界里立足。

人生不可能一帆风顺,有高峰自然有低谷,要相信,那些打不倒我们的,终将使我们更强大,要做自己的摆渡人。

我把自己这段时间整理的Android最重要最热门的学习方向资料放在了我的GitHub,里面还有不同方向的自学编程路线、面试题集合/面经、及系列技术文章等。

资源持续更新中,欢迎大家一起学习和探讨。

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值