有没有一个例子如何在Android中使用TouchDelegate来增加视图的点击目标的大小?

我的理解是,如果您的视图太小而不易触摸,则应该使用TouchDelegate来增加该视图的可点击区域。

但是,在Google上search使用示例时,出现了多个人问这个问题,但很less有答案。

有谁知道为视图设置触摸代理的正确方法,例如,在每个方向上增加其可点击区域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)); } }); 

我能够在一个屏幕上使用多个视图(checkbox)来完成这个任务,主要来自这篇博客文章 。 基本上你采取emmby的解决scheme,并将其应用到每个button和它的父母单独。

 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)); } }); } 

在我的情况下,我有一个gridviews与checkbox顶部覆盖的图像,并调用方法如下:

 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); 

为我工作很好。

这个解决scheme由@BrendanWeinstein发表在评论中。

而不是发送一个TouchDelegate你可以重写你的View getHitRect(Rect)方法(如果你正在扩展)。

 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)); } }); } 

也许它可以节省一些人的时间

给那个特定的组件(button)提供填充不是更好的想法。

晚会有点晚了,但经过很多研究,我现在使用:

 /** * 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); } }); } 

这比接受的解决scheme更好,因为它还允许在任何祖先视图上设置TouchDelegate,而不仅仅是父视图。

与接受的解决scheme不同,只要祖先视图的布局发生变化,它也会更新TouchDelegate。

如果不想以编程方式执行,则只需在图像周围创build透明区域,如果使用图像作为button的背景(视图)。

灰色区域可以是透明的,以增加触摸面积。

在这里输入图像说明

在大多数情况下,您可以在另一个无头视图(人造透明视图)中包装需要更大触摸区域的视图,并向包装视图添加填充/边距,并将点击/触摸连接到包装视图,而不是原始视图必须有一个更大的触摸面积。

据李梅森评论,这解决了我的问题。 我的项目有相对的布局和一个button。 所以父母是 – >布局和孩子是 – >一个button。

这里是谷歌链接示例谷歌代码

在删除他非常有价值的答案的情况下,我把这个答案放在这里。

最近我被问到如何使用TouchDelegate。 我自己有点生疏,我找不到任何好的文档。 这是我经过一些试验和错误后写的代码。 touch_delegate_view是一个简单的RelativeLayout,id为touch_delegate_root。 我定义了一个布局的单个子buttondelegated_button。 在这个例子中,我将button的可点击区域扩大到button顶部以上200像素。

公共类TouchDelegateSample扩展活动{

buttonmButton; @Override保护无效的onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState); 的setContentView(R.layout.touch_delegate_view); mButton =(Button)findViewById(R.id.delegated_button); 查看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); } } }); } } 

欢呼声,Justin Android Team @ Google

我的几句话:如果你想扩大左边你用减号给予价值,如果你想扩大对象的右边,你用加值赋予价值。 这与顶部和底部的作品是一样的。

通常只用很less的限制扩展触摸区域,请使用以下代码。

它可以让您扩大在给定的ancestor视图给定的view的触摸区域由给定的expansion像素。 只要给定的视图位于祖先布局树中,就可以select任何祖先。

  public static void expandTouchArea(final View view, final ViewGroup ancestor, final int expansion) { ancestor.post(new Runnable() { public void run() { Rect bounds = getRelativeBounds(view, ancestor); Rect expandedBounds = expand(bounds, expansion); // LOG.debug("Expanding touch area of {} within {} from {} by {}px to {}", view, ancestor, bounds, expansion, expandedBounds); ancestor.setTouchDelegate(new TouchDelegate(expandedBounds, view)); } private Rect getRelativeBounds(View view, ViewGroup ancestor) { Point relativeLocation = getRelativeLocation(view, ancestor); return new Rect(relativeLocation.x, relativeLocation.y, relativeLocation.x + view.getWidth(), relativeLocation.y + view.getHeight()); } private Point getRelativeLocation(View view, ViewGroup ancestor) { Point absoluteAncestorLocation = getAbsoluteLocation(ancestor); Point absoluteViewLocation = getAbsoluteLocation(view); return new Point(absoluteViewLocation.x - absoluteAncestorLocation.x, absoluteViewLocation.y - absoluteAncestorLocation.y); } private Point getAbsoluteLocation(View view) { int[] absoluteLocation = new int[2]; view.getLocationOnScreen(absoluteLocation); return new Point(absoluteLocation[0], absoluteLocation[1]); } private Rect expand(Rect rect, int by) { Rect expandedRect = new Rect(rect); expandedRect.left -= by; expandedRect.top -= by; expandedRect.right += by; expandedRect.bottom += by; return expandedRect; } }); } 

适用的限制:

  • 触摸区域不能超过视图祖先的界限,因为祖先必须能够捕捉触摸事件以便将其转发到视图。
  • 只能将一个TouchDelegate设置为ViewGroup 。 如果您想要使用多个触控代理,请select不同的祖先或使用组合触控代理,如“ 如何使用多个TouchDelegate”中所述 。

因为我不喜欢等待布局传递的想法,只是为了获得TouchDelegate矩形的新大小,所以我去了一个不同的解决scheme:

 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> 

这个想法是,TouchSizeIncreaser FrameLayout将包装微调(可以是任何子视图),并将所有触发事件捕获到它的命中rect到子View。 它适用于点击,即使点击超出范围,微调框也会打开,但不确定对其他更复杂的情况有什么影响。