我的理解是,当你的视图太小以至于很难触摸时,你应该使用TouchDelegate来增加该视图的可点击区域。
然而,在谷歌上搜索使用示例会得到多个人提出问题,但很少有答案。
有人知道设置触摸代理的正确方法吗?例如,将其可点击区域在每个方向上增加4像素。
我的理解是,当你的视图太小以至于很难触摸时,你应该使用TouchDelegate来增加该视图的可点击区域。
然而,在谷歌上搜索使用示例会得到多个人提出问题,但很少有答案。
有人知道设置触摸代理的正确方法吗?例如,将其可点击区域在每个方向上增加4像素。
我向 Google 的一位朋友询问并得到了帮助,他们帮我弄清了如何使用 TouchDelegate。这是我们想出来的方法:
final View parent = (View) delegate.getParent();
parent.post( new Runnable() {
// Post in the parent's message queue to make sure the parent
// lays out its children before we call getHitRect()
public void run() {
final Rect r = new Rect();
delegate.getHitRect(r);
r.top -= 4;
r.bottom += 4;
parent.setTouchDelegate( new TouchDelegate( r , delegate));
}
});
public static void expandTouchArea(final View bigView, final View smallView, final int extraPadding) {
bigView.post(new Runnable() {
@Override
public void run() {
Rect rect = new Rect();
smallView.getHitRect(rect);
rect.top -= extraPadding;
rect.left -= extraPadding;
rect.right += extraPadding;
rect.bottom += extraPadding;
bigView.setTouchDelegate(new TouchDelegate(rect, smallView));
}
});
}
CheckBox mCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox1);
final ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView1);
// Increase checkbox clickable area
expandTouchArea(imageView, mCheckBox, 100);
对我来说运作得非常好。
这个解决方案是由@BrendanWeinstein在评论中发布的。
你可以重写你的View
的getHitRect(Rect)
方法(如果你正在扩展一个),而不是发送一个 TouchDelegate
。
public class MyView extends View { //NOTE: any other View can be used here
/* a lot of required methods */
@Override
public void getHitRect(Rect r) {
super.getHitRect(r); //get hit Rect of current View
if(r == null) {
return;
}
/* Manipulate with rect as you wish */
r.top -= 10;
}
}
Emmby的方法对我不起作用,但经过一些小改动后就可以了:
private void initApplyButtonOnClick() {
mApplyButton.setOnClickListener(onApplyClickListener);
final View parent = (View)mApplyButton.getParent();
parent.post(new Runnable() {
@Override
public void run() {
final Rect hitRect = new Rect();
parent.getHitRect(hitRect);
hitRect.right = hitRect.right - hitRect.left;
hitRect.bottom = hitRect.bottom - hitRect.top;
hitRect.top = 0;
hitRect.left = 0;
parent.setTouchDelegate(new TouchDelegate(hitRect , mApplyButton));
}
});
}
I was recently asked about how to use a TouchDelegate. I was a bit rusty myself on this and I couldn't find any good documentation on it. Here's the code I wrote after a little trial and error. touch_delegate_view is a simple RelativeLayout with the id touch_delegate_root. I defined with a single, child of the layout, the button delegated_button. In this example I expand the clickable area of the button to 200 pixels above the top of my button.
public class TouchDelegateSample extends Activity { Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.touch_delegate_view); mButton = (Button)findViewById(R.id.delegated_button); View parent = findViewById(R.id.touch_delegate_root); // post a runnable to the parent view's message queue so its run after // the view is drawn parent.post(new Runnable() { @Override public void run() { Rect delegateArea = new Rect(); Button delegate = TouchDelegateSample.this.mButton; delegate.getHitRect(delegateArea); delegateArea.top -= 200; TouchDelegate expandedArea = new TouchDelegate(delegateArea, delegate); // give the delegate to an ancestor of the view we're delegating the // area to if (View.class.isInstance(delegate.getParent())) { ((View)delegate.getParent()).setTouchDelegate(expandedArea); } } }); } }
Cheers, Justin Android Team @ Google
我的建议是:如果您想扩展对象的左侧,可以使用负数值;如果您想扩展对象的右侧,可以使用正数值。同样的规则也适用于上下方向。
虽然有点晚了,但经过大量研究,我现在正在使用:
/**
* Expand the given child View's touchable area by the given padding, by
* setting a TouchDelegate on the given ancestor View whenever its layout
* changes.
*/*emphasized text*
public static void expandTouchArea(final View ancestorView,
final View childView, final Rect padding) {
ancestorView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
TouchDelegate delegate = null;
if (childView.isShown()) {
// Get hitRect in parent's coordinates
Rect hitRect = new Rect();
childView.getHitRect(hitRect);
// Translate to ancestor's coordinates
int ancestorLoc[] = new int[2];
ancestorView.getLocationInWindow(ancestorLoc);
int parentLoc[] = new int[2];
((View)childView.getParent()).getLocationInWindow(
parentLoc);
int xOffset = parentLoc[0] - ancestorLoc[0];
hitRect.left += xOffset;
hitRect.right += xOffset;
int yOffset = parentLoc[1] - ancestorLoc[1];
hitRect.top += yOffset;
hitRect.bottom += yOffset;
// Add padding
hitRect.top -= padding.top;
hitRect.bottom += padding.bottom;
hitRect.left -= padding.left;
hitRect.right += padding.right;
delegate = new TouchDelegate(hitRect, childView);
}
ancestorView.setTouchDelegate(delegate);
}
});
}
因为我不喜欢等待布局传递以获取TouchDelegate矩形的新大小的想法,所以我选择了另一种解决方案:
public class TouchSizeIncreaser extends FrameLayout {
public TouchSizeIncreaser(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final View child = getChildAt(0);
if(child != null) {
child.onTouchEvent(event);
}
return true;
}
}
<ch.tutti.ui.util.TouchSizeIncreaser
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp">
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</ch.tutti.ui.util.TouchSizeIncreaser>
我在Google Repo中找到的一个使用TouchDelegate的解决方案是这样实现的:
/**
* Ensures that the touchable area of [view] equal [minTouchTarget] by expanding the touch area
* of a view beyond its actual view bounds. This adapter can be used expand the touchable area of a
* view when other options (adding padding, for example) may not be available.
*
* Usage:
* <ImageView
* ...
* app:ensureMinTouchArea="@{@dimen/min_touch_target}"
*
* @param view The view whose touch area may be expanded
* @param minTouchTarget The minimum touch area expressed dimen resource
*/
@BindingAdapter("ensureMinTouchArea")
fun addTouchDelegate(view: View, minTouchTarget: Float) {
val parent = view.parent as View
parent.post {
val delegate = Rect()
view.getHitRect(delegate)
val metrics = view.context.resources.displayMetrics
val height = ceil(delegate.height() / metrics.density)
val width = ceil(delegate.width() / metrics.density)
val minTarget = minTouchTarget / metrics.density
var extraSpace = 0
if (height < minTarget) {
extraSpace = (minTarget.toInt() - height.toInt()) / 2
delegate.apply {
top -= extraSpace
bottom += extraSpace
}
}
if (width < minTarget) {
extraSpace = (minTarget.toInt() - width.toInt()) / 2
delegate.apply {
left -= extraSpace
right += extraSpace
}
}
parent.touchDelegate = TouchDelegate(delegate, view)
}
}
给那个组件(按钮)添加填充不是更好的想法吗?