사용자 정의 버튼 상태를 추가하는 방법


132

예를 들어 기본 버튼은 상태와 배경 이미지 사이에 다음과 같은 종속성이 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_window_focused="false" android:state_enabled="true"
        android:drawable="@drawable/btn_default_normal" />
    <item android:state_window_focused="false" android:state_enabled="false"
        android:drawable="@drawable/btn_default_normal_disable" />
    <item android:state_pressed="true" 
        android:drawable="@drawable/btn_default_pressed" />
    <item android:state_focused="true" android:state_enabled="true"
        android:drawable="@drawable/btn_default_selected" />
    <item android:state_enabled="true"
        android:drawable="@drawable/btn_default_normal" />
    <item android:state_focused="true"
        android:drawable="@drawable/btn_default_normal_disable_focused" />
    <item
        android:drawable="@drawable/btn_default_normal_disable" />
</selector>

어떻게 자신 만의 커스텀 상태를 정의 할 수 android:state_custom있습니까?


두 개의 암호 상자가 작은 체크 표시를 표시하기 위해 일치하는 시점을 결정하기 위해 EditText보기에 대한 추가 상태를 원했습니다.
Nathan

답변:


275

@ (Ted Hopp)로 표시된 솔루션은 작동하지만 약간의 수정이 필요합니다. 선택기에서 항목 상태에 "app :"접두사가 필요합니다. 그렇지 않으면 팽창기가 네임 스페이스를 올바르게 인식하지 못하고 자동으로 실패합니다. 적어도 이것은 나에게 일어나는 일입니다.

여기에 전체 솔루션을 좀 더 자세히 설명해 드리겠습니다.

먼저 "res / values ​​/ attrs.xml"파일을 작성하십시오.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="food">
        <attr name="state_fried" format="boolean" />
        <attr name="state_baked" format="boolean" />
    </declare-styleable>
</resources>

그런 다음 사용자 정의 클래스를 정의하십시오. 예를 들어, "Button"클래스에서 파생 된 "FoodButton"클래스 일 수 있습니다. 생성자를 구현해야합니다. 이 것을 구현하십시오. 인플레이터가 사용하는 것으로 보입니다.

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

파생 클래스 위에 :

private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};

또한 상태 변수 :

private boolean mIsFried = false;
private boolean mIsBaked = false;

그리고 두 세터 :

public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}

그런 다음 "onCreateDrawableState"함수를 재정의하십시오.

@Override
protected int[] onCreateDrawableState(int extraSpace) {
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
    if (mIsFried) {
        mergeDrawableStates(drawableState, STATE_FRIED);
    }
    if (mIsBaked) {
        mergeDrawableStates(drawableState, STATE_BAKED);
    }
    return drawableState;
}

마지막으로이 퍼즐의 가장 섬세한 부분입니다. 위젯의 배경으로 사용할 StateListDrawable을 정의하는 선택기 파일 "res / drawable / food_button.xml"입니다.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
    app:state_baked="true"
    app:state_fried="false"
    android:drawable="@drawable/item_baked" />
<item
    app:state_baked="false"
    app:state_fried="true"
    android:drawable="@drawable/item_fried" />
<item
    app:state_baked="true"
    app:state_fried="true"
    android:drawable="@drawable/item_overcooked" />
<item
    app:state_baked="false"
    app:state_fried="false"
    android:drawable="@drawable/item_raw" />
</selector>

"app :"접두사에 주목하고 표준 안드로이드 상태에서는 접두사 "android :"를 사용했을 것입니다. XML 네임 스페이스는 팽창기의 올바른 해석에 중요하며 속성을 추가하는 프로젝트 유형에 따라 다릅니다. 응용 프로그램 인 경우 com.mydomain.mypackage 를 응용 프로그램 의 실제 패키지 이름 (응용 프로그램 이름 제외)으로 바꾸십시오. 라이브러리 인 경우 "http://schemas.android.com/apk/res-auto"(및 도구 R17 이상 사용)를 사용해야합니다. 그렇지 않으면 런타임 오류가 발생합니다.

몇 가지 메모 :

  • "refreshDrawableState"함수를 호출 할 필요가없는 것 같습니다. 적어도 제 경우에는 솔루션이 제대로 작동합니다.

  • 레이아웃 xml 파일에서 사용자 정의 클래스를 사용하려면 정규화 된 이름 (예 : com.mydomain.mypackage.FoodButton)을 지정해야합니다.

  • 더 복잡한 상태 조합을 나타 내기 위해 사용자 정의 상태와 혼합 표준 상태 (예 : android : pressed, android : enabled, android : selected)를 만들 수 있습니다.


3
업데이트 : 사용자 정의 클래스가 Button이 아닌 TextView에서 파생되는 경우 refreshDrawableState를 호출 해야하는 것으로 보이며 그렇지 않으면 위젯 모양이 업데이트되지 않습니다. 전화는 세터에 두어야한다. 나는 다른 수업을 시도하지 않았습니다. froyo 장치에서 수행 된 테스트.
Giorgio Barchiesi

17
refreshDrawableState확실히 중요하다. 그것이 정말로 필요할 때 확실하지 않습니다. 그러나 제 경우에는 프로그래밍 방식으로 상태를 설정할 때 필요했습니다. onTouchEvent의 View 클래스에서 자동으로 호출 될 수 있습니다. setSelected 메소드에 추가하는 것이 좋습니다.
buergi

1
GiorgioBarchiesi에는 두 개의 사용자 정의 버튼이 있으며 한 버튼의 onClick 이벤트에서 두 버튼의 상태를 변경하려고하면 클릭 한 버튼 만 변경됩니다. @ buergi가 refreshDrawableState 메서드가 onClickEvent. 훌륭한 튜토리얼에 다시 한번 감사드립니다 :)
Bolton

2
그러나 그렇지 않은 사용자 지정 상태를 어떻게 사용할 수 boolean있습니까? 아니면 선택기가 부울에서만 작동합니까?
Peterdk

2
어떻게 작동합니까? 내 말은, 속성이 true / false로 업데이트되는 방법은 무엇입니까? 누가 업데이트합니까? 로컬 변수가 true 인 경우에만 drawablestate를 병합하면 상태 또는 속성 값이 업데이트됩니까? 어떤 코드가 R.attr.state_fried를 정확하게 업데이트합니까?
kAmol

10

이 스레드 는 버튼 등에 사용자 정의 상태를 추가하는 방법을 보여줍니다. 브라우저에서 새 Google 그룹을 볼 수 없으면 여기 에 스레드 사본이 있습니다 .


고마워요, 테드! 지금은 문제의 근원이 사라져서 실제 구현에 도달하지 못했습니다. 그러나 고객이 다시이 문제로 돌아 오면 내가 지적한 방식으로 시도해 보겠습니다.
Vit Khudenko

정확히 내가 필요한 것 같은데, 내 사용자 지정 상태에 대한 그러나 국가 목록 드로어 블은 ... 내가 모르는 뭔가가 있어야합니다 변경되지 않습니다
나단 Schwermann

refreshDrawableState ()를 호출하고 있습니까?
테드 pp

연결이 끊어졌습니다.
미치

@ 미치-글쎄, 너무 나쁘다. 대체 링크를 찾을 수 있는지 살펴 보겠습니다. 그렇지 않은 경우 기본적으로 그대로 쓸모가 없으므로이 답변을 삭제하겠습니다. 한편, 허용 된 답변에는 필요한 모든 정보가 있습니다.
테드 홉

6

refreshDrawableStateUI 스레드 내 에서 호출하는 것을 잊지 마십시오 .

mHandler.post(new Runnable() {
    @Override
    public void run() {
        refreshDrawableState();
    }
});

모든 것이 올바르게 보이지만 버튼이 왜 상태를 변경하지 않는지 알아내는 데 많은 시간이 걸렸습니다.


이 핸들러는 언제 또는 언제 게시해야합니까?
Arthur Melo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.