Android使用TouchDelegate增加View的触摸范围

by sgwhp,转载请注明。


还不知道TouchDelegate这个东西的可以先看一下API,这里大致说一下它的作用:假设有两个View,分别是v1,v2,我们可以通过v1的setTouchDelegate(bounds, v2)来委派触摸事件,其中bounds是一个Rect。v1中,落在这个范围的TouchEvent都会传给v2。

既然是这样,那我们可以通过设置某个view的parent的touchDelegate来达到扩大这个view触摸范围的目的。关键是什么时候去执行parent.setTouchDelegate()方法呢?要设置这个委派,必须得知道当前view大小以及它在parent的位置。而这些数据都是在onLayout才能确定(注:如果不是自定义View,只是在Activity中设置,请将这些操作置于onWindowFocusChanged()方法中)。至此,实现的思路已经很清晰了,我们通过自定义一个Button来检验一下,下面开始上代码:

为了方便在xml中使用我们自定义的View,并且可以自定义扩大的触摸范围,我们再自定义一个attrs,res/values/attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="LargeTouchableAreaView">
        <attr name="addition" format="dimension" />
        <attr name="additionBottom" format="dimension" />
        <attr name="additionLeft" format="dimension" />
        <attr name="additionRight" format="dimension" />
        <attr name="additionTop" format="dimension" />
    </declare-styleable>
</resources>

Button实现:

public class LargeTouchableAreasButton extends Button {
	private final int TOUCH_ADDITION = 0;
	private int mTouchAdditionBottom = 0;
	private int mTouchAdditionLeft = 0;
	private int mTouchAdditionRight = 0;
	private int mTouchAdditionTop = 0;
	private int mPreviousLeft = -1;
	private int mPreviousRight = -1;
	private int mPreviousBottom = -1;
	private int mPreviousTop = -1;

	public LargeTouchableAreasButton(Context context) {
		super(context);
	}

	public LargeTouchableAreasButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public LargeTouchableAreasButton(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);
		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.LargeTouchableAreaView);
		int addition = (int) a.getDimension(
				R.styleable.LargeTouchableAreaView_addition, TOUCH_ADDITION);
		mTouchAdditionBottom = addition;
		mTouchAdditionLeft = addition;
		mTouchAdditionRight = addition;
		mTouchAdditionTop = addition;
		mTouchAdditionBottom = (int) a.getDimension(
				R.styleable.LargeTouchableAreaView_additionBottom,
				mTouchAdditionBottom);
		mTouchAdditionLeft = (int) a.getDimension(
				R.styleable.LargeTouchableAreaView_additionLeft,
				mTouchAdditionLeft);
		mTouchAdditionRight = (int) a.getDimension(
				R.styleable.LargeTouchableAreaView_additionRight,
				mTouchAdditionRight);
		mTouchAdditionTop = (int) a.getDimension(
				R.styleable.LargeTouchableAreaView_additionTop,
				mTouchAdditionTop);
		a.recycle();
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		if (left != mPreviousLeft || top != mPreviousTop
				|| right != mPreviousRight || bottom != mPreviousBottom) {
			mPreviousLeft = left;
			mPreviousTop = top;
			mPreviousRight = right;
			mPreviousBottom = bottom;
			final View parent = (View) this.getParent();
			parent.setTouchDelegate(new TouchDelegate(new Rect(left
					- mTouchAdditionLeft, top - mTouchAdditionTop, right
					+ mTouchAdditionRight, bottom + mTouchAdditionBottom), this));
		}
	}

}
然后在具体要使用到这个Button的xml中加上以下代码:

xmlns:lta="http://schemas.android.com/apk/res/com.xxx.xxx"
其中"lta"这个名字可以随便取,最后的是你的app包名。

最后在这个Button中定义希望增大的尺寸:

<com.xxx.LargeTouchableAreasButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        lta:addition="30dp" />
大功告成。


但这个自定义的View并不是完美的,还存在以下问题:

1、必须保证parent足够大,如果自定义的范围超出parent的大小,则超出的那部分无效。

2、一个parent只能设置一个触摸委派,设置多个时,只有最后设置的child有效。如果希望一个view能设置多个委派,需要再自定义parent,具体方法可参考:http://cyrilmottier.com/2012/02/16/listview-tips-tricks-5-enlarged-touchable-areas/

总而言之,要触发委派,必须保证parent接收到了触摸事件,并且落在了你定义的范围内。

你可能感兴趣的:(Android使用TouchDelegate增加View的触摸范围)