1. 前言
早些时候我发了一篇关于对话框动画的文章全网独一份的对话框弹出样式。用户阅读量,分享量,阅读后关注量等数据比较好。与之前偏重Android源码解析的文章不同,那是一篇更偏实战的文章。美中不足的是,代码注释量很少,有读者反馈阅读体验不佳。如果这个问题也曾困扰过你,借此向您真诚道歉,由于行文仓促,没有投入更多精力,今后在文章润色上投入更多时间,争取为读者带来更好的阅读体验。
如果您觉得我的文章写的还行,帮我点个在看,或者分享出去,您的支持是我最大的动力。如果您有好的建议,欢迎您在留言区留言。
2. 关于TouchDelegate
本文内容不仅限于TouchDelegate的简单使用,也会涉及到原理讲解,它的局限性以及解决方案。
工作中,可能会遇到这种情况
❝设计师:"呀,你这个按钮点击太不灵敏了,能不能把点击区域放大一点?"
开发:"我这个按钮大小,跟你设计稿上标注的一样大呀!要不然你把图片切大一点?"
❞
修改按钮大小,当然可以扩大按钮的点击区域,在不修改按钮大小的前提下,能否做到扩大按钮的点击区域呢?
当然可以,用TouchDelegate就能做到。
2.1 核心方法
- TouchDelegate(Rect bounds, View delegateView)
View delegateView:指需要扩大点击区域的控件。
Rect bounds:指delegateView响应事件的区域,一般比它的原始范围要大。
- View#setTouchDelegate(TouchDelegate delegate)
TouchDelegate是View.java的成员变量。View对象一般是delegateView的祖先控件(不仅仅是父控件,可以是祖先控件)
2.2 场景
场景一:父控件区域足够大,扩大单个Button点击范围
如下图,将Button的点击区域扩大500像素
代码如下
「这样设置,那么在绿色区域内点击,Button按钮同样能够响应到点击事件。
场景二:父控件区域很小,扩大单个Button点击范围
粉红色ViewGroup区域只比Button大一点,将Button点击区域扩大500像素。
如果调用ViewGroup.setTouchDelegate()则没效果,需要调用Root.setTouchDelegate()。
「某ViewGroup想扩大它的后代View的点击区域,必须保证ViewGroup有足够的空间,否则寻找空间足够大的祖先控件来扩大后代View的点击区域」
场景三:同时有多个Button想扩大点击区域
如下图,同时扩大Button1、Button2的点击区域500像素
「也许你可能会说,这还不简单吗?我信手拈来,写下如下代码」
「但是很不幸运,只有button2的点击区域扩大了500像素,button1的点击区域并没有扩大,这是系统默认的TouchDelegate的局限性,只能给一个后代View扩大点击区域,后面我将给出解决方案」
场景四:扩大点击区域的Button周围填充了其它View
伪代码如下,假设left、top等View的宽高刚好是500像素
「当用户点击在left、top等View上,即使已经将Button1的点击扩大了500px,Button1也无法获取点击事件。因为只有当ViewGroup的所有子View都不处理事件,才会轮到TouchDelegate去分发事件。这涉及到事件分发机制具体请参考 深度遍历讲解Android事件分发机制」
3. 原理分析
3.1 核心方法
- View.onTouchEvent(MotionEvent event)
- 如果设置了TouchDelegate,则调用它的onTouchEvent,如果返回true,调用结束,否则往下走
- 处理OnClickListener,OnLongClickListener等事件
- TouchDelegate.onTouchEvent(MotionEvent event)
- Down事件,判断手指是否落在事件扩大范围内
- 非Down事件,判断手指是否超出了slopBounds,slopBounds是在bounds的区域上再扩大一定的范围,如果超出,向delegateView发送一个负值事件坐标
- 如果分发事件,将事件坐标设置为delegateView的中心点
- 如果手指超出了最大范围,将事件坐标设置为负值分发
4. DEMO代码
demo已上传至https://github.com/lizijin/zijiexiaozhan。由于国内网络环境问题,有可能需要自备梯子访问。如果您无法获取代码,请私信我。
运行截图如下
5. 突破局限
场景三:同时有多个Button想扩大点击区域,我们讲到,系统的TouchDelegate无法同时给多个View设置扩大点击区域。
假设有如下需求,想同时扩大加购和减购的点击区域,该如何做呢?
最终效果如下。如图,点击在加减购周围,同样能够触发事件。
核心代码,重写TouchDelegate。
完整代码已上传至https://github.com/lizijin/zijiexiaozhan。由于国内网络环境问题,有可能需要自备梯子访问。如果您无法获取代码,请私信我。
6. 总结
- 盲区一:设置TouchDelegate,必须在需要扩大点击区域的View的祖先View上。
- 盲区二:如果祖先View空间,比子View需要的区域还小,无法正确扩大点击区域。
- 盲区三:如果View周边有其它的View消耗事件,那么扩大点击区域可能无效。
- 盲区四:系统默认情况,无法给多个View扩大点击区域。
最后:码字不易。帮忙点个在看,或者分享给朋友。感激涕零。