¿Cómo declaro un elemento de la interfaz de usuario de Android usando XML?
¿Cómo declaro un elemento de la interfaz de usuario de Android usando XML?
Respuestas:
La Guía para desarrolladores de Android tiene una sección llamada Creación de componentes personalizados . Desafortunadamente, la discusión de los atributos XML solo cubre declarar el control dentro del archivo de diseño y no manejar los valores dentro de la inicialización de la clase. Los pasos son los siguientes:
values\attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
<attr name="android:text"/>
<attr name="android:textColor"/>
<attr name="extraInformation" format="string" />
</declare-styleable>
</resources>
Observe el uso de un nombre no calificado en la declare-styleable
etiqueta. Los atributos de Android no estándar como extraInformation
deben tener su tipo declarado. Las etiquetas declaradas en la superclase estarán disponibles en subclases sin tener que volver a declararlas.
Como hay dos constructores que usan una AttributeSet
inicialización, es conveniente crear un método de inicialización separado para que los constructores llamen.
private void init(AttributeSet attrs) {
TypedArray a=getContext().obtainStyledAttributes(
attrs,
R.styleable.MyCustomView);
//Use a
Log.i("test",a.getString(
R.styleable.MyCustomView_android_text));
Log.i("test",""+a.getColor(
R.styleable.MyCustomView_android_textColor, Color.BLACK));
Log.i("test",a.getString(
R.styleable.MyCustomView_extraInformation));
//Don't forget this
a.recycle();
}
R.styleable.MyCustomView
es un int[]
recurso autogenerado donde cada elemento es la ID de un atributo. Los atributos se generan para cada propiedad en el XML agregando el nombre del atributo al nombre del elemento. Por ejemplo, R.styleable.MyCustomView_android_text
contiene el android_text
atributo para MyCustomView
. Los atributos se pueden recuperar del TypedArray
uso de varias get
funciones. Si el atributo no está definido en el definido en el XML, null
se devuelve. Excepto, por supuesto, si el tipo de retorno es primitivo, en cuyo caso se devuelve el segundo argumento.
Si no desea recuperar todos los atributos, es posible crear esta matriz manualmente. La ID para los atributos estándar de Android están incluidos android.R.attr
, mientras que los atributos para este proyecto están incluidos R.attr
.
int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};
Tenga en cuenta que usted debe no usar nada en android.R.styleable
, según este hilo se puede cambiar en el futuro. Todavía está en la documentación, ya que es útil ver todas estas constantes en un solo lugar.
layout\main.xml
Incluya la declaración del espacio de nombres xmlns:app="http://schemas.android.com/apk/res-auto"
en el elemento xml de nivel superior. Los espacios de nombres proporcionan un método para evitar los conflictos que a veces ocurren cuando diferentes esquemas usan los mismos nombres de elementos (consulte este artículo para obtener más información). La URL es simplemente una forma de identificar esquemas de forma única: en realidad no es necesario alojar nada en esa URL . Si parece que esto no está haciendo nada, es porque en realidad no necesita agregar el prefijo del espacio de nombres a menos que necesite resolver un conflicto.
<com.mycompany.projectname.MyCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="Test text"
android:textColor="#FFFFFF"
app:extraInformation="My extra information"
/>
Haga referencia a la vista personalizada con el nombre completo.
Si desea un ejemplo completo, mire la muestra de vista de etiqueta de Android.
TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
CharSequences=a.getString(R.styleable.LabelView_text);
<declare-styleable name="LabelView">
<attr name="text"format="string"/>
<attr name="textColor"format="color"/>
<attr name="textSize"format="dimension"/>
</declare-styleable>
<com.example.android.apis.view.LabelView
android:background="@drawable/blue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:text="Blue" app:textSize="20dp"/>
Esto está contenido en un LinearLayout
atributo con un espacio de nombres:xmlns:app="http://schemas.android.com/apk/res-auto"
Gran referencia ¡Gracias! Una adición a esto:
Si tiene un proyecto de biblioteca incluido que ha declarado atributos personalizados para una vista personalizada, debe declarar el espacio de nombres de su proyecto, no el de la biblioteca. P.ej:
Dado que la biblioteca tiene el paquete "com.example.library.customview" y el proyecto de trabajo tiene el paquete "com.example.customview", entonces:
No funcionará (muestra el error "error: no se encontró un identificador de recurso para el atributo 'newAttr' en el paquete 'com.example.library.customview'"):
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
android:id="@+id/myView"
app:newAttr="value" />
Trabajará:
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.customview"
android:id="@+id/myView"
app:newAttr="value" />
xmlns:app="http://schemas.android.com/apk/res-auto"
Vea el comentario 57 en code.google.com/p/android/issues/detail?id=9656
Suspicious namespace: Did you mean http://schemas.android.com/apk/res-auto
res-auto
porque estamos usando Android Studio y Gradle. De lo contrario (por ejemplo, algunas versiones de Eclipse) generalmente terminaría en lib/[your package name]
. iehttp://schemas.android.com/apk/lib/[your package name]
Adición a la respuesta más votada.
Quiero agregar algunas palabras sobre el uso de getStyledAttributes (), cuando creamos una vista personalizada usando android: xxx atributos predefinidos. Especialmente cuando usamos TextAppearance.
Como se mencionó en "2. Crear constructores", la vista personalizada obtiene AttributeSet en su creación. Uso principal que podemos ver en el código fuente de TextView (API 16).
final Resources.Theme theme = context.getTheme();
// TextAppearance is inspected first, but let observe it later
TypedArray a = theme.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = a.getIndex(i);
// huge switch with pattern value=a.getXXX(attr) <=> a.getXXX(a.getIndex(i))
}
a.recycle();
¿Qué podemos ver aquí?
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
El conjunto de atributos se procesa por tema de acuerdo con la documentación. Los valores de los atributos se compilan paso a paso. Los primeros atributos se llenan del tema, luego los valores se reemplazan por los valores del estilo y, finalmente, los valores exactos de XML para la instancia de vista especial reemplazan a otros.
Matriz de atributos solicitados: com.android.internal.R.styleable.TextView
es una matriz ordinaria de constantes. Si estamos solicitando atributos estándar, podemos construir esta matriz manualmente.
Lo que no se menciona en la documentación: orden de los elementos TypedArray de resultados.
Cuando se declara una vista personalizada en attrs.xml, se generan constantes especiales para los índices de atributos. Y podemos extraer los valores de esta manera: a.getString(R.styleable.MyCustomView_android_text)
. Pero para el manual int[]
no hay constantes. Supongo que getXXXValue (arrayIndex) funcionará bien.
Y otra pregunta es: "¿Cómo podemos reemplazar las constantes internas y solicitar atributos estándar?" Podemos usar los valores de android.R.attr. *.
Entonces, si queremos usar el atributo TextAppearance estándar en una vista personalizada y leer sus valores en el constructor, podemos modificar el código de TextView de esta manera:
ColorStateList textColorApp = null;
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
Resources.Theme theme = context.getTheme();
TypedArray a = theme.obtainStyledAttributes(attrs, R.styleable.CustomLabel, defStyle, 0);
TypedArray appearance = null;
int apResourceId = a.getResourceId(R.styleable.CustomLabel_android_textAppearance, -1);
a.recycle();
if (apResourceId != -1)
{
appearance =
theme.obtainStyledAttributes(apResourceId, new int[] { android.R.attr.textColor, android.R.attr.textSize,
android.R.attr.typeface, android.R.attr.textStyle });
}
if (appearance != null)
{
textColorApp = appearance.getColorStateList(0);
textSize = appearance.getDimensionPixelSize(1, textSize);
typefaceIndex = appearance.getInt(2, -1);
styleIndex = appearance.getInt(3, -1);
appearance.recycle();
}
Donde se define CustomLabel:
<declare-styleable name="CustomLabel">
<!-- Label text. -->
<attr name="android:text" />
<!-- Label text color. -->
<attr name="android:textColor" />
<!-- Combined text appearance properties. -->
<attr name="android:textAppearance" />
</declare-styleable>
Tal vez, estoy equivocado de alguna manera, pero la documentación de Android en getStyledAttributes () es muy pobre.
Al mismo tiempo, solo podemos extender el componente de interfaz de usuario estándar, utilizando todos sus atributos declarados. Este enfoque no es tan bueno, porque TextView, por ejemplo, declara muchas propiedades. Y será imposible implementar la funcionalidad completa en anular onMeasure () y onDraw ().
Pero podemos sacrificar la reutilización teórica de componentes personalizados. Diga "Sé exactamente qué características usaré" y no comparta código con nadie.
Entonces podemos implementar constructor CustomComponent(Context, AttributeSet, defStyle)
. Después de llamar super(...)
tendremos todos los atributos analizados y disponibles a través de métodos getter.
Parece que Google ha actualizado su página de desarrollador y ha agregado varios entrenamientos allí.
Uno de ellos se ocupa de la creación de vistas personalizadas y se puede encontrar aquí.
Muchas gracias por la primera respuesta.
En cuanto a mí, solo tuve un problema con eso. Al inflar mi vista, tuve un error: java.lang.NoSuchMethodException: MyView (Context, Attributes)
Lo resolví creando un nuevo constructor:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// some code
}
Espero que esto ayude!
Puede incluir cualquier archivo de diseño en otro archivo de diseño como-
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="30dp" >
<include
android:id="@+id/frnd_img_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_imagefile"/>
<include
android:id="@+id/frnd_video_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_video_lay" />
<ImageView
android:id="@+id/downloadbtn"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:src="@drawable/plus"/>
</RelativeLayout>
aquí los archivos de diseño en la etiqueta de inclusión son otros archivos de diseño .xml en la misma carpeta res.