배경을 조정하지 않고 Android 버튼의 히트 영역을 늘리는 방법은 무엇입니까?


83

커스텀 드로어 블이있는 버튼이 있습니다.

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

드로어 블은 배경이 투명한 삼각형입니다.

|\
| \
|__\

이 버튼을 누르기가 어렵습니다. 첫째, 상대적으로 작습니다. 둘째, 투명 픽셀은 탭할 수 없습니다. 드로어 블을 같은 크기로 유지하고 싶지만 히트 영역을 삼각형 크기의 두 배로 정사각형 모양으로 만듭니다.

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

1
마진도 히트 영역을 증가시키지 않았습니다.
JoJo 2011

패딩을 사용해보십시오. 확실히 작동합니다.
Arjun Vyas 2019

답변:


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
여기에서 값이 어떻게 설정됩니까? button.getHitRect (rect)에 반환 값이 없습니다!
amitavk

@ amitav13 rect이 매개 변수로 전달됩니다.
not_again_stackoverflow

이봐, 당신이 사용하는 100 값, 내가 치수 폴더에서 얻은 dp 값이어야합니까? 밀도에 따라 값이 변할까요?
j2emanue jul.

@ 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 내부에 추가됩니다. 따라서이 버튼은 여전히 ​​22x23 크기입니다. 그래서 이것은 도움이되지 않습니다.
Simon Warta

1
이것은 훌륭하게 작동합니다. 패딩은 탭할 수있는 영역을 원하는대로 확장하고 JoJo (원작자)가 요청한 것과 같은 크기로 내 이미지를 남겼습니다.
Alyoshak

이 답변이 너무 많은 찬성표를 얻은 이유는 패딩이 바깥 쪽이 아닌 테두리 안쪽의 내용을 채우는 것이 분명합니까?!
Farid

1
이전 의견에 이어 배경이 확대 될 것이라고 생각합니다. 그렇다면 아마도 "삽입"드로어 블 안에 배경을 넣을 수 있습니다. 추신. 나는 TouchDelegate보다 이것을 선호하는데, TouchDelegate는 조상을 엉망으로 만들어야하고 자식보기가 움직이면 더 복잡해지기 때문입니다.
Henry

24

당신은 사용할 필요가 TouchDelegate"실제 뷰 범위보다 더 큰 터치 영역을 가지고 당신이보기를 원하는 핸들 상황에 도우미 클래스"로 API 문서에 정의 된을,

http://developer.android.com/reference/android/view/TouchDelegate.html


@mxcl,이 답변을 유효하지 않거나 "잘못된"것으로 렌더링하는 귀하의 의견에 아무것도 없습니다.
dbm

7
에 대한 설명 TouchDelegate및 스 니펫 코드 : developer.android.com/training/gestures/viewgroup.html#delegate
Brais Gabin 2014-07-08

16

이 솔루션을 선호합니다.

레이아웃 리소스 파일에 양수 여백과 음수 여백을 추가하기 만하면됩니다.

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

이것은 TouchDelegates 사용에 비해 매우 작은 변화입니다. 또한 Java 코드 내부에 클릭 가능한 영역을 추가하기 위해 Runnable을 실행하고 싶지 않습니다.

뷰가 픽셀 완벽해야하는 경우 고려할 수있는 한 가지 : 패딩 이 항상 margin 과 같을 수는 없습니다 . 패딩 지정된 항상 정확히이 있어야합니다. 마진 주변 뷰에 의존하여 오프셋 될 마진 다른보기의 값.


이 사람을 사랑했습니다 : D
Ayman Salah

이 작업을 수행 할 수 없습니다. LinearLayout에 두 개의 텍스트가 나란히 있고 오른손이 텍스트 자체보다 조금 더 큰 터치 가능한 영역을 갖기를 원합니다. 가는
기비

@Kibi 단일 뷰 (여기 TextView)를에 삽입 LinearLayout할 필요가 없습니다. 그럼에도 불구하고이 두 줄을 LinearLayout? 앞에서 언급했듯이 여백은 주변 전망에 따라 다릅니다.
티모 바르

@ TimoBähr에게 감사하지만 (처음에는) 전체 LinearLayout이 클릭 가능한 것을 원하지 않았습니다. 왼쪽의 텍스트가 clickablr이 아니었기 때문에 ... 결국 나는 전체 LinearLayout Clickable을 화나게 만들었습니다. 공장.
Kibi

9

답변을 바탕으로 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태그를 사용할 수 있습니다.


6

데이터 바인딩을 사용하는 경우. 바인딩 어댑터를 사용할 수 있습니다.

@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 Y로 나타나야하지만 히트 영역은 X + 10 x Y + 10이어야한다는 것입니다. 투명 픽셀이 히트 영역에 추가되지 않는다고 생각합니다. 내 그래픽은 삼각형 모양입니다. 투명 영역을 탭하면 onClick이 트리거되지 않습니다.
조조

배경 이미지의 투명한 픽셀이 히트 영역에 추가 될 것임을 확신합니다. 보이지 않는 버튼을 만들기 위해 전에 사용했습니다. 높이와 너비를 하드 코딩했기 때문에 크기가 추가되지 않을 수도 있습니다. 아마도 wrap_content를 사용해보십시오.
FoamyGuy 2011

이상 해요. 테스트를 위해 버튼을 부풀려 전체 화면을 채웠습니다. 불투명 픽셀을 탭하면 LogCat이 내 onClick 로그를 인쇄합니다. 투명 영역을 탭하면 등록되지 않습니다.
JoJo 2011

또한 손가락 표면 영역이 버튼의 표면 영역보다 크도록 화면에 많은 압력을 가하면 onClick이 트리거되지 않습니다. onClick을 트리거하려면 버튼을 조심스럽게 탭해야합니다. 이 "뚱뚱한 손가락 증후군"을 조정하는 속성이 있습니까?
JoJo 2011

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" />

이 ideia 좋아 .. 깨끗하고 .. 간단한 .. 당신이 중심에 맞게 패딩과 당김 작업 할 수 있습니다 .. 좋은 ..
길 헤르 메 올리베이라


1

이것은 나를 위해 일했습니다.

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

실제로 30을 딥으로 변환하거나 버튼 높이의 백분율을 수행해야합니다.


설명이 필요합니다. OP는 Button (일부 뷰의 레이아웃 xml의 일부)에 대한 레이아웃 xml의 스 니펫을 게시했습니다. 하지만 위의 메서드는 버튼이 포함 된 뷰 클래스가 아니라 버튼과 연결되어야한다고 가정합니다. 위의 방법을 해당 버튼과 어떻게 연결합니까?
ToolmakerSteve

1

버튼의 이미지보다 더 큰 클릭 가능한 영역이 필요했습니다. 배경 드로어 블보다 큰 FrameLayout으로 감싸고 내부 Button 태그를 TextView로 변경했습니다. 클릭 핸들러가 내부 TextView가 아닌이 FrameLayout과 함께 작동하도록 지시 한 것보다. 모두 잘 작동합니다!


끔찍하지만 이것은 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대신
바딤 Kotov에게

0

이를 위해 ImageButton을 사용했습니다. xml 방어에서 다음 두 가지 속성을 볼 수 있습니다.

  • android : 배경 으로 사용할 드로어 블입니다.
  • android : scr- 이 ImageView의 콘텐츠로 드로어 블을 설정합니다.

그래서 우리는 두 개의 드로어 블을 가지고 있습니다 : 배경 1과 소스. 예제 소스는 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

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의 ​​기본 / 상위 요소에 추가 해야합니다.

예제 완료 :

<?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

정답은 Button 대신 ImageButton을 사용해야한다고 생각합니다. 삼각형 드로어 블을 ImageButton의 "src"로 설정하고 원하는대로 크기 (layout_width & layout_height)를 설정하고 삼각형 크기를 유지하려면 ScaleType을 가운데로 설정합니다.


0

솔직히 가장 쉬운 방법은 다음과 같습니다.

이미지 크기가 26dp * 26dp이고 히트 영역이 30dp * 30dp가 필요하다고 가정하고 ImageButton / 버튼에 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입니다. 여백을 추가하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.