如何在不缩放背景的情况下增加Android按钮的点击区域?


82

我有一个带有自定义绘图的按钮。

<Button
    android:layout_width="22dip"
    android:layout_height="23dip"
    android:background="@drawable/triangle" />

可绘制对象是具有透明背景的三角形。

|\
| \
|__\

我发现此按钮很难点击。首先,它相对较小。其次,透明像素不可轻拍。我想将可绘制对象的大小保持相同,但将点击区域设置为正方形,是三角形大小的两倍。

_____________
|            |
|    |\      |
|    | \     |
|    |__\    |
|____________|

1
保证金也没有增加命中区域。
JoJo

尝试使用填充。它肯定会工作。
Arjun Vyas

Answers:


68

您可以使用TouchDelegate API。

final View parent = (View) button.getParent();  // button: the view you want to enlarge hit area
parent.post( new Runnable() {
    public void run() { 
        final Rect rect = new Rect(); 
        button.getHitRect(rect); 
        rect.top -= 100;    // increase top hit area
        rect.left -= 100;   // increase left hit area
        rect.bottom += 100; // increase bottom hit area           
        rect.right += 100;  // increase right hit area
        parent.setTouchDelegate( new TouchDelegate( rect , button)); 
    } 
}); 

1
值如何在此处设置为rect?button.getHitRect(rect)没有返回值!
阿米塔夫克16-4-13

@ amitav13rect作为参数传递。
not_again_stackoverflow

嘿,您使用的100值,应该是我从Dimensions文件夹获得的dp值吗?值会根据密度变化吗?
j2emanue

@ j2emanue是的。您还可以通过编程方式进行计算stackoverflow.com/a/8399445/2523667
Nicolas

45

您需要“填充”,它将在视图内部放置空间。保证金会将空间放到外面,这不会增加点击区域。

 <Button
    android:layout_width="22dip"
    android:layout_height="23dip"
    android:background="@drawable/triangle"
    android:padding="10dp" />

我在设备和仿真器上进行了测试,但无法正常工作。你测试过了吗?
LiangWang

18
填充添加在layout_width / layout_height内部,而不是外部。因此,此Button仍为22x23大。因此,这无济于事。
西蒙·沃塔

1
这很好。填充根据需要扩展了可轻按的区域,并使我的图像具有相同的大小,就像JoJo(原始作者)所要求的那样。
Alyoshak

为什么这个答案获得了如此多的赞誉,很明显,填充内容在边界之内而不在边界之内?!
Farid

1
遵循我先前的评论,我认为这也会扩大背景。如果是这样,也许您可​​以将背景放在“插图”可绘制对象中。PS。我比TouchDelegate更喜欢它,因为TouchDelegate需要弄乱祖先,并且如果子视图正在移动,它将变得更加复杂...
亨利


16

我更喜欢这种解决方案:

只需在布局资源文件中添加正填充和负空白:

<some.View
  ..
  android:padding="12dp"
  android:margin="-12dp"
  .. />

与TouchDelegates的用法相比,这是很小的变化。我也不想运行Runnable在Java代码中添加clickable区域。

您可能会考虑的一件事是,视图是否应该是像素完美的:填充不能总是等于margin填充应始终完全位于指定位置。的余量依赖于周围的意见,并且将与偏移余量的其它视图的值。


喜欢这个:D
Ayman Salah

无法解决这个问题。我在LinearLayout中有两个彼此相邻的文本,并且希望右手具有比文本本身大一点的可触摸区域...但是使用这两条额外的行会使我的文本偏移,这不是我的外观参加
Kibi

@Kibi不需要将单个视图(此处为TextView)插入LinearLayout。但是,您是否尝试过将这两行添加到您的LinearLayout?如前所述,保证金取决于周围的观点。
TimoBähr16年

谢谢@TimoBähr,但是(最初)我不希望整个LinearLayout是可单击的,因为左侧的文本不应该是可点击的...最后,我猛跳并疯狂了整个LinearLayout可单击的,当然,作品。
基比

8

基于答案,我创建了一个kotlin扩展功能来帮助它。

/**
 * Increase the click area of this view
 */
fun View.increaseHitArea(dp: Float) {
    // increase the hit area
    val increasedArea = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().displayMetrics).toInt()
    val parent = parent as View
    parent.post {
        val rect = Rect()
        getHitRect(rect)
        rect.top -= increasedArea
        rect.left -= increasedArea
        rect.bottom += increasedArea
        rect.right += increasedArea
        parent.touchDelegate = TouchDelegate(rect, this)
    }
}


6

只需在按钮上添加填充

 <Button
android:layout_width="wrap_contant"
android:layout_height="wrap_contant"
android:background="@drawable/triangle"
android:padding="20dp" />

因此,通过执行此操作,您的按钮将获取三角形图像的高度和宽度,并将20dp填充添加到按钮上,而无需拉伸图像本身。如果您需要最小宽度或最大高度,可以使用minWidthminHeight标签


5

如果您正在使用数据绑定。您可以使用绑定适配器。

@BindingAdapter("increaseTouch")
fun increaseTouch(view: View, value: Float) {
    val parent = view.parent
    (parent as View).post({
        val rect = Rect()
        view.getHitRect(rect)
        val intValue = value.toInt()
        rect.top -= intValue    // increase top hit area
        rect.left -= intValue   // increase left hit area
        rect.bottom += intValue // increase bottom hit area
        rect.right += intValue  // increase right hit area
        parent.setTouchDelegate(TouchDelegate(rect, view));
    });
}

然后可以在这样的视图上使用属性

increaseTouch="@{8dp}"

2

我不确定“不增加背景可绘制对象”的含义。如果您只是不想让可绘制对象拉伸,那么您可以采用的一种方法就是将背景png加上一个额外的透明像素边框。这会增加您的点击范围,但不会拉伸您的图像。

但是,如果您表示根本不想更改该可绘制对象,那么我认为您唯一的选择是对高度和宽度使用较大的硬编码值。


我的意思是我需要按钮图形以X X出现,但点击区域是X + 10 X Y + 10。我认为透明像素不会增加点击区域。我的图形是三角形。当我点击透明区域时,onClick不会触发。
乔乔

我确定背景img中的透明像素将添加到点击区域。我以前用它来制作一个隐形按钮。也许不是因为您已经对高度和宽度进行了硬编码而没有增加尺寸?也许尝试那些的wrap_content。
FoamyGuy 2011年

真奇怪。我按下按钮以填充整个屏幕,仅用于测试。当我点击不透明像素时,LogCat会打印出我的onClick日志。当我点击透明区域时,它不会注册。
JoJo

另外,如果您在屏幕上施加了很大的压力,以使手指的表面积大于按钮的表面积,则不会触发onClick。我必须小心翼翼地点击按钮以触发onClick。是否有任何属性可以调节这种“肥胖手指综合症”?
JoJo

2

试试这个

  <Button
        android:id="@+id/btn_profile"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:background="@android:color/transparent"
        android:drawableBottom="@drawable/moreoptionicon"
        android:onClick="click"
        android:paddingBottom="15dp"
        android:visibility="visible" />

喜欢这个想法..干净..简单..您可以使用填充和可绘制使其适合中心位置..不错..
Guilherme Oliveira


1

这对我有用:

public void getHitRect(Rect outRect) {
    outRect.set(getLeft(), getTop(), getRight(), getBottom() + 30);
}

虽然确实应该将30转换为dip或按按钮高度的一定百分比进行转换。


需要解释。OP为Button发布了一个布局xml的摘要(这将是某些视图的布局xml的一部分)。但是我认为上述方法需要与Button关联,而不是与包含按钮的视图类关联?您如何将上述方法与该按钮关联?
制造商史蒂夫(Steve)2015年

1

我只需要一个相同的地方:可点击区域大于按钮的图像。我将其包装到大于背景可绘制大小的FrameLayout中,并将内部Button标记更改为TextView。比起我指导单击处理程序来处理此FrameLayout,而不是与内部TextView一起使用。一切正常!


尽管可怕,但这是Android提供的最佳解决方案。
i_am_jorf

1

您可以像这样使用透明按钮...

<Button
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:background="@android:color/transparent" /> 

您可以根据需要增加或减小按钮的大小,并enter code here在按钮上使用ImageView。

<ImageView
    android:layout_width="22dip"
    android:layout_height="23dip"
    android:background="@drawable/triangle" />

1

我在kotlin中为此创建了顶层函数:

fun increaseTouchArea(view: View, increaseBy: Int) {
    val rect = Rect()
    view.getHitRect(rect)
    rect.top -= increaseBy    // increase top hit area
    rect.left -= increaseBy   // increase left hit area
    rect.bottom += increaseBy // increase bottom hit area
    rect.right += increaseBy  // increase right hit area
    view.touchDelegate = TouchDelegate(rect, view)
}

2
您可以View改为创建扩展功能
Vadim Kotov,

0

为此,我使用了ImageButton。在xml防御中,您将看到以下两个属性:

  • android:background一个可绘制的背景。
  • android:scr-设置一个drawable作为此ImageView的内容。

因此,我们有两个可绘制对象:背景一和源。在您的示例中,源将为triagle(drawable / trianlge):

|\
| \
|__\

背景为正方形(可绘制/正方形):

_____________
|            |
|            |
|            |
|            |
|____________|

这是ImageButton xml的示例:

<ImageButton
   ...
   android:src="@drawable/triangle"
   android:background="@drawable/square">

结果:

_____________
|            |
|    |\      |
|    | \     |
|    |__\    |
|____________|

同样是正方形可绘制的,可以具有几种不同的状态(按下,聚焦)。您可以使用填充来扩展背景可绘制大小。

以防万一,下面是可从Android Compat Actionbar绘制背景的示例:

<?xml version="1.0" encoding="utf-8"?>    
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
    <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_disabled_holo_dark" />
    <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/abc_list_selector_disabled_holo_dark" />
    <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_dark" />
    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/abc_list_selector_background_transition_holo_dark" />
    <item android:state_focused="true" android:drawable="@drawable/abc_list_focused_holo" />
    <item android:drawable="@android:color/transparent" />
 </selector>

由于某些原因,即使背景只是透明的,我的src也没有被使用。
MLProgrammer-CiM 2014年

0

您可以将填充设置为视图,即按钮。

<Button
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@android:color/transparent"
        android:padding="15dp" />

希望这对您有用。


0

因此,正确的答案是,在可触摸区域添加填充以增大尺寸,并将图片从背景更改为srcCompact

<Button
    android:layout_width="22dip"
    android:layout_height="23dip"
    android:padding="6dp"
    app:srcCompat="@drawable/triangle"/>

要使用app:scrCompat,您需要添加xmlns:app="http://schemas.android.com/apk/res-auto"到xml中的main / parent元素中。

示例完成:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/height_btn_bottom_touch_area"
android:background="@color/bg_white"
android:clipToPadding="false"
android:elevation="7dp">

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:stateListAnimator="@animator/selected_raise"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" >

    <ImageView
        android:id="@+id/bottom_button_bg"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:contentDescription=
            "@string/service_request_background_contentDescription"
        android:elevation="1dp"
        android:padding="6dp"
        app:srcCompat="@drawable/btn_round_blue"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" >
    </ImageView>

    <TextView
        android:id="@+id/bottom_button_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:elevation="1dp"
        android:gravity="center"
        android:text="@string/str_continue_save"
        android:textColor="@color/text_white"
        android:textSize="@dimen/size_text_title"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

0

只是添加填充导致我的复选框未居中。以下内容对我有用,但是我为复选框指定了固定大小(根据我的UI规范)。想法是在左侧而不是右侧添加填充。我还在顶部和底部添加了填充,以使触摸目标更大,并且仍保持复选框居中。

<CheckBox
        android:id="@+id/checkbox"
        android:layout_width="30dp"
        android:layout_height="45dp"
        android:paddingLeft="15dp"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:button="@drawable/checkbox"
        android:checked="false"
        android:gravity="center"
       />

0

我认为正确的答案应该是使用ImageButton而不是Button。将三角形可绘制区域设置为ImageButton的“ src”,并根据需要设置大小(layout_width和layout_height),以便于触摸,并将ScaleType设置为居中以保留三角形大小。


0

老实说,我认为最简单的方法是:

假设您的图片大小为26dp * 26dp,并且想要的点击区域为30dp * 30dp,只需在ImageButton / Button中添加2dp的填充,并将尺寸设置为30dp * 30dp


原版的

<ImageButton
    android:layout_width="26dp"
    android:layout_height="26dp"
    android:src="@drawable/icon"/>

命中区域更大

<ImageButton
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:padding="2dp"
    android:src="@drawable/icon_transcript"/>

0

最简单的解决方案是增加width and height商品的数量(例如图片,按钮等)并添加padding; 因此,可点击区域较大,但看起来是原始大小。

例:

<Button
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:padding="8dp"
    android:background="@drawable/triangle" />

恭喜,您获得了相同的按钮尺寸,但可点击尺寸增加了一倍!

_____________
|            |
|    |\      |
|    | \     |
|    |__\    |
|____________|

-2
<Button
    android:layout_width="32dp"
    android:layout_height="36dp"
    android:layout_margin="5dp"
    android:background="@drawable/foo" 
/>

背景尺寸仍为22x26dp。只需添加保证金即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.