with values type tutorial studio example enum android xml android-layout android-custom-view

values - enums android studio



Android: ¿Es posible usar string/enum en el selector dibujable? (3)

Lo sentimos, no puede crear objetos dibujables personalizados en xml: https://groups.google.com/d/msg/android-developers/glpdi0AdMzI/LpW4HGMB3VIJ

Preguntas

P1 : ¿Alguien ha logrado obtener un atributo de cadena / enumeración personalizado trabajando en los selectores xml? Obtuve un atributo booleano que funciona siguiendo [1], pero no un atributo de cadena.

EDIT: Gracias por las respuestas. Actualmente, Android solo admite selectores booleanos. Ver respuesta aceptada por el motivo.

Estoy planeando implementar un pequeño botón personalizado complejo, cuya apariencia depende de dos variables. Otro será un atributo booleano (verdadero o falso) y otro atributo similar a una categoría (tiene muchos valores posibles diferentes). Mi plan es usar atributos booleanos y de cadena (¿o tal vez enumerar?). Esperaba poder definir la interfaz de usuario en el selector xml utilizando los atributos boolean y string.

P2 : ¿Por qué en [1] el onCreateDrawableState (), los atributos booleanos se combinan solo si son verdaderos?

Esto es lo que he probado, el atributo booleano funciona, la cadena no

NOTA : Esta es solo una aplicación de prueba para averiguar si es posible el atributo cadena / enumeración en el selector xml. Sé que podría establecer el color de texto del botón sin un atributo personalizado.

En mi aplicación de demostración, utilizo un atributo booleano para establecer el fondo del botón en oscuro / brillante y el atributo de cadena para configurar el color del texto, uno de {"rojo", "verde", "azul"}. Los atributos se definen en /res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyCustomButton"> <attr name="make_dark_background" format="boolean" /> <attr name="str_attr" format="string" /> </declare-styleable> </resources>

Aquí están los selectores que quiero lograr:

@ drawable / custom_button_background (que funciona)

<?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.example.customstringattribute"> <item app:make_dark_background="true" android:drawable="@color/dark" /> <item android:drawable="@color/bright" /> </selector>

@ color / custom_button_text_color (que no funciona)

<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/com.example.customstringattribute"> <item app:str_attr="red" android:color="@color/red" /> <item app:str_attr="green" android:color="@color/green" /> <item app:str_attr="blue" android:color="@color/blue" /> <item android:color="@color/grey" /> </selector>

Aquí se muestra cómo el fondo del botón personalizado se conecta al selector booleano y el color del texto se conecta al selector de cadena.

<com.example.customstringattribute.MyCustomButton ... android:background="@drawable/custom_button_background" android:textColor="@color/custom_button_text_color" ... />

Aquí es cómo se cargan los atributos en el método init ():

private void init(AttributeSet attrs) { TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyCustomButton); final int N = a.getIndexCount(); for (int i = 0; i < N; ++i) { int attr = a.getIndex(i); switch (attr) { case R.styleable.MyCustomButton_str_attr: mStrAttr = a.getString(attr); break; case R.styleable.MyCustomButton_make_dark_background: mMakeDarkBg = a.getBoolean(attr, false); break; } } a.recycle(); }

Tengo las matrices int [] para los atributos

private static final int[] MAKE_DARK_BG_SET = { R.attr.make_dark_background }; private static final int[] STR_ATTR_ID = { R.attr.str_attr };

Y esas matrices int [] se fusionan en un estado dibujable

@Override protected int[] onCreateDrawableState(int extraSpace) { Log.i(TAG, "onCreateDrawableState()"); final int[] drawableState = super.onCreateDrawableState(extraSpace + 2); if(mMakeDarkBg){ mergeDrawableStates(drawableState, MAKE_DARK_BG_SET); } mergeDrawableStates(drawableState, STR_ATTR_ID); return drawableState; }

También tengo refreshDrawableState () en mis métodos de establecimiento de atributos:

public void setMakeDarkBg(boolean makeDarkBg) { if(mMakeDarkBg != makeDarkBg){ mMakeDarkBg = makeDarkBg; refreshDrawableState(); } } public void setStrAttr(String str) { if(mStrAttr != str){ mStrAttr = str; refreshDrawableState(); } }

[1]: Cómo agregar un estado de botón personalizado


Q1:

No lo he intentado yo mismo, pero:

¿Ha intentado colocar su @color/custom_button_text_color.xml en la carpeta @color/custom_button_text_color.xml ? (Solo para estar seguros, hay un poco de magia de carpetas aquí y allá en Android y no estoy seguro de esto).

Q2:

Hay dos casos de uso para conjuntos de estados. Una de ellas es declarar explícitamente selectores para elementos dibujables con estado mediante programación. En este caso, para los selectores, debe poder decirle a Android que use este dibujable si no se establece un atributo. Para expresar esto, puede incluir los criterios negados (precedidos por un signo menos) en el int[] .

Si bien esto apenas se menciona en el contexto de los criterios de selección, nunca se menciona para los estados dibujables en sí mismos (también conocido como la representación del estado del dibujable). Por lo tanto, uno definitivamente está en el lado seguro si no incluye las ID de estado negadas en el conjunto; Las implementaciones de Android provistas tampoco las incluyen.


Q1:

Cuando abre el código fuente de StateListDrawable.java, puede ver este fragmento de código en el método de inflado que lee el selector de XML extraíble: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/drawable/StateListDrawable.java

... for (i = 0; i < numAttrs; i++) { final int stateResId = attrs.getAttributeNameResource(i); if (stateResId == 0) break; if (stateResId == com.android.internal.R.attr.drawable) { drawableRes = attrs.getAttributeResourceValue(i, 0); } else { states[j++] = attrs.getAttributeBooleanValue(i, false) ? stateResId : -stateResId; } } ...

attrs son los atributos de cada <item> en el <selector> .

En este for-loop obtiene los atributos de android:state_xxxx , varios android:state_xxxx y personalizados app:xxxx . Todos menos los atributos de android:drawable parecen interpretarse como booleanos solamente: attrs.getAttributeBooleanValue(....) se llama.

Creo que esta es la respuesta, basada en el código fuente:

Solo puede agregar atributos booleanos personalizados a su xml, no a ningún otro tipo (incluidos los enumerados).

Q2:

No estoy seguro de por qué el estado se fusiona solo si se establece específicamente en verdadero. Sospecho que el código debería tener este aspecto:

private static final int[] MAKE_DARK_BG_SET = { R.attr.make_dark_background }; private static final int[] NOT_MAKE_DARK_BG_SET = { -R.attr.make_dark_background }; .... .... @Override protected int[] onCreateDrawableState(int extraSpace) { Log.i(TAG, "onCreateDrawableState()"); final int[] drawableState = super.onCreateDrawableState(extraSpace + 2); mergeDrawableStates(drawableState, mMakeDarkBg? MAKE_DARK_BG_SET : NOT_MAKE_DARK_BG_SET); //mergeDrawableStates(drawableState, STR_ATTR_ID); return drawableState; }