lunes, 29 de noviembre de 2010

Crear un componente personalizado desde XML [Android]

Los componentes personalizados de Android nos permiten personalizar elementos de interfaz, bien modificándolos o bien agrupando varios en un único componente que podamos reutilizar. La documentación de Android denomina a este tipo de controles compuestos a su vez de varios controles estándar de Android Compound Components. Se explica cómo construir uno de estos controles en el código Java de una nueva clase, pero no queda muy claro cómo podríamos construir el componente si quisieramos utilizar uno de los ficheros de interfaz XML.

Para hacerlo, empezaríamos definiendo la interfaz en un fichero XML, que en mi caso sería /res/layout/elementos_lista.xml. En este caso vamos a hacer algo sencillo: un cuadro de texto con un botón.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_width="fill_parent"> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:layout_height="50px" android:id="@+id/edit_persona" android:layout_width="fill_parent" android:layout_weight="1"></EditText> <Button android:id="@+id/btn_agenda" android:layout_height="50px" android:layout_width="fill_parent" android:layout_weight="3" android:text="Agenda"></Button> </LinearLayout> </LinearLayout>

Con esto creamos una clase en nuestra carpeta src que extienda a la clase LinearLayout y desde la que cargaremos ese fichero XML en su constructor. Como queremos que el botón ejecute una acción (en este caso imprimir algo por pantalla) definimos también un OnClickListener con la manejadora del click sobre el botón.

package ocode.apps.aleatorizr; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; public class ElementosListaComponent extends LinearLayout { public OnClickListener agendaHandler = new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(v.getContext(), "click en el botón agenda", Toast.LENGTH_SHORT).show(); } }; public ElementosListaComponent(Context context) { super(context); } public ElementosListaComponent(Context context, AttributeSet attr){ super(context,attr); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); LinearLayout vistaCompuesta = (LinearLayout) inflater.inflate(R.layout.elementos_lista, this); Button btn_agenda = (Button) vistaCompuesta.findViewById(R.id.btn_agenda); btn_agenda.setOnClickListener(agendaHandler); } }

Lo importante de este código está ocurriendo en el segundo constructor, que por medio de LayoutInflater procesa el código XML de la interfaz del componente para que lo tengamos accesible para ser utilizado desde cualquier otra vista del programa. Con esto hecho, si quisiesemos utilizarlo en otro layout sólo tendremos que abrir dicho layout y utilizar el siguiente código:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:text="Selecciona uno" android:id="@+id/txt_pic" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView> <ocode.apps.aleatorizr.ElementosListaComponent android:layout_width="fill_parent" android:layout_height="wrap_content"> </ocode.apps.aleatorizr.ElementosListaComponent> </LinearLayout>

2 comentarios:

  1. Hola tengo una duda me tira este error en la clase con el control personalizado, esperando una respuesta
    Me dice la dirección de la clase en el Layout

    error:
    The following classes could not be instantiated:
    - ocode.apps.aleatorizr.ElementosListaComponent (Open Class, Show Error Log)
    See the Error Log (Window > Show View) for more details.
    Tip: Use View.isInEditMode() in your custom views to skip code when shown in Eclipse

    java.lang.NullPointerException
    at ocode.apps.aleatorizr.ElementosListaComponent.(ElementosListaComponent.java:30)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0( at sun.reflect.NativeConstructorAccessorImpl.newInstance( at sun.reflect.DelegatingConstructorAccessorImpl.newInstance( at java.lang.reflect.Constructor.newInstance( at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.instantiateClass(ProjectCallback.java:422)
    at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.loadView(ProjectCallback.java:179)
    at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:207)
    at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:135)
    at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:746)
    at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:718)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:372)

    ResponderEliminar
  2. Geniaaaal era lo que buscaba :3 te amo <3

    ResponderEliminar