2010-12-02 5 views
100

Например, кнопка по умолчанию имеет следующие зависимости между его состояниями и фоновыми изображениями:Как добавить пользовательское состояние кнопки

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

Как определить свое собственное состояние (SMTH как android:state_custom), так потом Я мог бы использовать его для динамического изменения внешнего вида кнопки?

+0

Я хотел получить дополнительные состояния для вида EditText, чтобы определить, когда два поля для паролей соответствуют маленькой галочке. – schwiz 2010-12-23 22:07:53

ответ

222

Решение, указанное компанией @ (Ted Hopp), работает, но нуждается в небольшой коррекции: в селекторе item требует префикса «app:», иначе надуватель не будет правильно распознавать пространство имен и будет терпеть неудачу; по крайней мере, это то, что происходит со мной.

Позвольте мне сообщить здесь все решения, еще с некоторыми деталями:

Во-первых, создать файл "Рез/значения/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> 

Затем определите свой собственный класс. Например, это может быть класс «FoodButton», полученный из класса «Button». Вам нужно будет реализовать конструктор; реализовать этот, который, кажется, один используется Inflater:

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; 

И несколько сеттеров:

Затем переопределить функцию "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, который вы будете использовать в качестве фона для вашего виджета. Это файл «Рез/рисуем/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> 

Обратите внимание на «приложение:» префикс, в то время как со стандартными андроида состояниями вы бы использовали приставку «андроид:». Пространство имен XML имеет решающее значение для правильной интерпретации надувателем и зависит от типа проекта, в котором вы добавляете атрибуты. Если это приложение, замените com.mydomain.mypackage с фактическим именем вашего приложения (исключение имени приложения). Если это библиотека, вы должны использовать «http://schemas.android.com/apk/res-auto» (и использовать инструменты R17 или новее), или вы получите ошибки времени выполнения.

Несколько примечаний:

  • Кажется, вам не нужно вызывать функцию «refreshDrawableState», по крайней мере, решение хорошо работает как в моем случае

  • Для того, чтобы использовать свой собственный класс в XML-файле макета, вам нужно будет указать полное имя (например, com.mydomain.mypackage.FoodButton)

  • Вы можете, как Weel потасовка стандартные состояния (например, андроид: нажимается, андроид: включен, андроид: выбран) с пользовательскими состояниями, для того, чтобы представить более сложные государственные комбинации

9

This thread показывает, как добавлять пользовательские состояния к кнопкам и тому подобное. (Если вы не видите новые группы Google в своем браузере, есть копия потока here.)

+0

+1 спасибо большое, Тед! Прямо сейчас происхождение проблемы ушло, поэтому я не дошел до фактической реализации. Однако, если мой клиент снова вернется к этому, я попробую, как вы указали мне. – 2010-12-21 08:23:06

+0

Выглядит точно так же, как мне нужно, однако чертежи списка состояний для моих пользовательских состояний меняются. Я должен что-то пропускать ... – schwiz 2010-12-24 06:10:22

5

Пожалуйста, не забудьте позвонить refreshDrawableState в UI потоке:

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

потребовалось много моего времени, чтобы понять, почему моя кнопка не меняет свое состояние, даже если все выглядит правильно.

Смежные вопросы