使用android.view.TouchDelegate扩大View的触摸点击区域

Android4.0设计规定的有效可触摸的UI元素标准是48dp,转化为一个物理尺寸约为9毫米。7~10毫米,这是一个用户手指能准确并且舒适触摸的区域。

如下图所示,你的UI元素可能小于48dp,图标仅有32dp,按钮仅有40dp,但是他们的实际可操作焦点区域最好都应达到48dp的大小。

1 触屏手机点击区域的小秘密

为使小的UI区域获得良好的触摸交互,根据View的特性,目前碰到了两种情况:

1.如ImageView,设置其padding值,可触摸区域将向外扩展;

2.如Button,设置其padding值,可触摸区域不变,其内内容显示区域向内压缩;


情况1的控件,可直接设置其padding值达到目的,如 android:padding="10dp"  

情况2的控件,可使用TouchDelegate动态修改其触摸区域,达到扩大点击范围的效果

/**
	 * 扩大View的触摸和点击响应范围,最大不超过其父View范围
	 * 
	 * @param view
	 * @param top
	 * @param bottom
	 * @param left
	 * @param right
	 */
	public static void expandViewTouchDelegate(final View view, final int top,
			final int bottom, final int left, final int right) {

		((View) view.getParent()).post(new Runnable() {
			@Override
			public void run() {
				Rect bounds = new Rect();
				view.setEnabled(true);
				view.getHitRect(bounds);

				bounds.top -= top;
				bounds.bottom += bottom;
				bounds.left -= left;
				bounds.right += right;

				TouchDelegate touchDelegate = new TouchDelegate(bounds, view);

				if (View.class.isInstance(view.getParent())) {
					((View) view.getParent()).setTouchDelegate(touchDelegate);
				}
			}
		});
	}

采取此种方法的两点注意:

1、若View的自定义触摸范围超出Parent的大小,则超出的那部分无效。
2、一个Parent只能设置一个View的TouchDelegate,设置多个时只有最后设置的生效。


若需要恢复该View的触摸范围:

/**
	 * 还原View的触摸和点击响应范围,最小不小于View自身范围
	 * 
	 * @param view
	 */
	public static void restoreViewTouchDelegate(final View view) {

		((View) view.getParent()).post(new Runnable() {
			@Override
			public void run() {
				Rect bounds = new Rect();
				bounds.setEmpty();
				TouchDelegate touchDelegate = new TouchDelegate(bounds, view);

				if (View.class.isInstance(view.getParent())) {
					((View) view.getParent()).setTouchDelegate(touchDelegate);
				}
			}
		});
	}

使用TouchDelegate扩大View的触摸响应范围是一种比较灵活的方法,有时可与设置padding的方式结合使用。

更新

======

后期实际开发中发现,使用post runnable的方式去设置Delegate区域大小的原因是,如该View师在Activity的OnCreate()或Fragment的OnCreateView()中绘制,此时UI界面尚未开始绘制,无法获得正确的坐标;

若将此法应用在ListView的getView()中绘制每个ItemView时,则Delegate的设置将部分失效,原因是ListView的绘制较特殊,可能无法获取到部分还未绘制出的View的正确坐标。解决方案具体可参考以下参考阅读所列。


参考阅读:通过自定义View的方式,及某些其他情况的处理:

1.《Android使用TouchDelegate增加View的触摸范围》 http://blog.youkuaiyun.com/sgwhp/article/details/10963383

2.《ListView Tips & Tricks #5: Enlarged Touchable Areas》 http://cyrilmottier.com/2012/02/16/listview-tips-tricks-5-enlarged-touchable-areas/

3.《Extend touchable areas #Android》 https://plus.google.com/u/0/+JulienDodokal/posts/8zoV3RQvReS

<think>嗯,用户想在Android中通过scaleX属性实现View的等比缩放。首先,我需要回忆一下AndroidView的缩放相关属性。scaleX和scaleY是控制View在X轴和Y轴上的缩放比例,但单独使用scaleX可能无法保持宽高比,容易导致变形。所以用户的问题是如何在设置scaleX的同时保持等比缩放,也就是说需要同时调整scaleY,让两者的值相同。 根据引用中的资料,比如引用3提到双指缩放时保持X和Y比例一致,使用postScale方法同时设置相同的缩放因子。这说明等比缩放的关键是确保scaleX和scaleY的值相同。不过用户提到的是使用scaleX属性,可能是指通过XML属性或者View的属性方法来实现。 接下来,看看用户提供的引用内容。引用2中的代码示例展示了如何根据设计图尺寸计算缩放后的X和Y值,虽然这里的缩放是基于屏幕适配的,但原理上也是保持比例一致。引用4提到对View进行缩放处理时需要注意坐标偏移的问题,这可能影响到缩放后的布局位置。 用户的问题需要具体的实现方法,可能需要结合代码示例来说明。首先,要明确scaleX和scaleY属性本身是View的属性,可以通过setScaleX和setScaleY方法来设置。为了保证等比缩放,需要同时设置这两个属性为相同的值。例如,设置scaleX为0.5时,scaleY也应该设置为0.5。 另外,需要注意的是,直接使用scaleX和scaleY进行缩放时,View的布局参数(如宽度和高度)可能不会改变,这会导致周围元素的布局可能受到影响,因为缩放只是视觉上的变换,不会改变View的实际占位。因此,如果需要在缩放后调整布局位置,可能需要结合其他方法,比如修改布局参数或使用平移变换。 引用3中的代码使用了Matrix的postScale方法,并同时设置了相同的缩放因子,这也是保持等比的另一种方式。但用户的问题是关于scaleX属性的使用,所以可能需要比较这两种方法的区别。使用Matrix进行变换通常用于自定义View的绘制过程,而scaleX和scaleY属性是View自带的属性,适用于普通的View对象。 可能还需要考虑动画效果,比如用户希望有一个平滑的缩放动画,这时候可以使用属性动画,同时设置scaleX和scaleY的属性值。例如,使用ObjectAnimator对scaleX和scaleY同时进行动画处理,保持相同的缩放比例。 此外,引用4提到的处理View的偏移量问题,可能需要在使用缩放时调整View的位置,以确保缩放后的View相对于父容器的位置正确。例如,缩放后的View可能会因为中心点位置的变化而需要重新计算其显示位置。 总结实现步骤:首先,确定缩放的比率;然后,同时设置scaleX和scaleY为该比率;最后,处理可能的布局位置调整。如果需要动态计算比率,可以参考引用2中的方法,根据屏幕尺寸和设计图尺寸计算合适的缩放比例。 最后,要提醒用户注意,单纯使用scaleX和scaleY进行缩放可能会影响View触摸事件区域,因为虽然View看起来缩小了,但它的点击区域可能仍然是原始大小。如果需要调整触摸区域,可能需要进一步处理。</think>### 通过scaleX属性实现View等比缩放的方法 在Android中,使用`scaleX`和`scaleY`属性实现**等比缩放**需要保持两个方向缩放比例一致。以下是具体实现步骤和注意事项: --- #### 1. **直接设置缩放比例** 若需固定比例缩放(如缩小为50%),直接同步设置`scaleX`和`scaleY`属性: ```kotlin view.scaleX = 0.5f view.scaleY = 0.5f ``` 此时View会以中心点为锚点进行等比缩放[^3]。 --- #### 2. **动态计算缩放比例** 若需根据屏幕尺寸动态适配(如基于设计稿1920x1080适配不同屏幕),参考以下方法: ```kotlin // 计算X轴缩放比例 fun calculateScaleX(targetWidth: Int): Float { return targetWidth.toFloat() / Config.width // Config.width为设计稿宽度 } // 应用等比缩放 val scale = calculateScaleX(screenWidth) view.scaleX = scale view.scaleY = scale ``` 此方法确保View在X/Y轴方向按相同比例缩放[^2]。 --- #### 3. **结合动画实现平滑缩放** 使用属性动画实现动态等比缩放效果: ```kotlin val scaleAnimator = ObjectAnimator.ofPropertyValuesHolder( view, PropertyValuesHolder.ofFloat("scaleX", 1f, 0.8f), PropertyValuesHolder.ofFloat("scaleY", 1f, 0.8f) ) scaleAnimator.duration = 300 scaleAnimator.start() ``` --- #### 4. **处理缩放后的布局偏移** 缩放可能导致View位置偏移,需修正坐标: ```kotlin view.pivotX = 0f // 设置锚点为左上角 view.pivotY = 0f view.scaleX = 0.7f view.scaleY = 0.7f ``` 通过调整`pivotX/pivotY`可控制缩放锚点,避免位置异常[^4]。 --- ### 关键注意事项 1. **触摸事件区域**:缩放后View点击区域仍为原始尺寸,需通过`TouchDelegate`扩展点击区域 2. **性能优化**:避免在`onDraw`中频繁计算缩放比例,建议在初始化阶段完成计算 3. **与Matrix缩放的区别**:`scaleX/scaleY`直接修改View属性,而`Matrix`作用于绘制阶段,两者可结合使用 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值