避坑系列其他文章:
Android 避坑指南:实际经历来说说IdleHandler的坑
1
关于TouchDelegate
本文内容不仅限于TouchDelegate的简单使用,也会涉及到原理讲解,它的局限性以及解决方案。
工作中,可能会遇到这种情况
❝设计师:"呀,你这个按钮点击太不灵敏了,能不能把点击区域放大一点?"
开发:"我这个按钮大小,跟你设计稿上标注的一样大呀!要不然你把图片切大一点?"
❞
修改按钮大小,当然可以扩大按钮的点击区域,在不修改按钮大小的前提下,能否做到扩大按钮的点击区域呢?
当然可以,用TouchDelegate就能做到。
1.1 核心方法
1、TouchDelegate(Rect bounds, View delegateView)
View delegateView:指需要扩大点击区域的控件。
Rect bounds:指delegateView响应事件的区域,一般比它的原始范围要大。
2、View#setTouchDelegate(TouchDelegate delegate)
TouchDelegate是View.java的成员变量。View对象一般是delegateView的祖先控件(不仅仅是父控件,可以是祖先控件)。
1.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事件分发机制」
2
原理分析
2.1 核心方法
1、View.onTouchEvent(MotionEvent event)
-
如果设置了TouchDelegate,则调用它的onTouchEvent,如果返回true,调用结束,否则往下走
-
处理OnClickListener,OnLongClickListener等事件
2、TouchDelegate.onTouchEvent(MotionEvent event)
-
Down事件,判断手指是否落在事件扩大范围内。
-
非Down事件,判断手指是否超出了slopBounds,slopBounds是在bounds的区域上再扩大一定的范围,如果超出,向delegateView发送一个负值事件坐标。
-
如果分发事件,将事件坐标设置为delegateView的中心点。
-
如果手指超出了最大范围,将事件坐标设置为负值分发。
3
DEMO代码
demo已上传至
https://github.com/lizijin/zijiexiaozhan
运行截图如下
4
突破局限
场景三:同时有多个Button想扩大点击区域,我们讲到,系统的TouchDelegate无法同时给多个View设置扩大点击区域。
假设有如下需求,想同时扩大加购和减购的点击区域,该如何做呢?
最终效果如下。如图,点击在加减购周围,同样能够触发事件。
核心代码,重写TouchDelegate。
完整代码已上传至
https://github.com/lizijin/zijiexiaozhan
5
总结
1、盲区一:设置TouchDelegate,必须在需要扩大点击区域的View的祖先View上。
2、盲区二:如果祖先View空间,比子View需要的区域还小,无法正确扩大点击区域。
3、盲区三:如果View周边有其它的View消耗事件,那么扩大点击区域可能无效。
4、盲区四:系统默认情况,无法给多个View扩大点击区域。