Construcción de un control personalizado en Android
Introducción
En muchas ocasiones es muy interesante crear nuestros propios controles personalizados para poder reutilizarlos rápida y cómodamente en el futuro.
En este tutorial vamos a ver un ejemplo de como crear y usar un control personlizado sencillo.
Manos a la obra! construcción del control personalizado
A continuación construiremos un control que nos permita cómodamente elegir mediante una barra de progreso un número entre un determinado intervalo válido, además nos permita personalizar:
- El título
- El valor máximo.
- El valor por defecto seleccionado.
Si deseas el código fuente, puedes descargártelo aquí .
(Está autocomentado, no creo que tengas problemas si tienes una base de programación en Android.)
Captura de pantalla de la aplicación a construir:
El control personalizado que construiremos está resaltado con un borde azul.
Interface gráfico de la aplicación (la captura de pantalla)
Observe como definimos declarativamente la pantalla con el control personalizado es.carlosgarcia.widget.SeekBarCustom
que construiremos posteriormente:
es.carlosgarcia.MainActivity
Único Activity de la aplicación.
package es.carlosgarcia; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import es.carlosgarcia.widget.SeekBarCustom; /** * Control personalizado que representa una barra de progreso con un título con: * @param min: Valor mánimo * @param progress: Valor actual * @param text: Título mostrado * @author Carlos García. http://www.carlos-garcia.es */ public class MainActivity extends Activity implements OnClickListener { private Button btn; private SeekBarCustom seek; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.main); this.btn = (Button) this.findViewById(R.id.button1); this.seek = (SeekBarCustom) this.findViewById(R.id.barId); this.btn.setOnClickListener(this); } /** * Cuando hacemos clic en el botón invocamos un método personalizado y especifico del control */ @Override public void onClick(View v) { if (seek.isValueSelected()){ Toast.makeText(this, "Estupendo!!", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "Seleccione un valor, por favor.", Toast.LENGTH_LONG).show(); } } }
es.carlosgarcia.widget.SeekBarCustom
Clase que define el control personalizado que deseamos construir (lo resaltado en azul en la captura de pantalla anterior).
Observe como:
- Construimos el control combinando (o componiendo) varios controles ya definidos (LinearLayout, SeekBar y TextView)
- Leemos los atributos que hemos definido en el XML del GUI. (max, progress, text).
package es.carlosgarcia.widget; import android.content.Context; import android.util.AttributeSet; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; /** * Control personalizado que representa una barra de progreso con un título con: * @param min: Valor mínimo * @param progress: Valor actual * @param text: Título mostrado * @author Carlos García. http://www.carlos-garcia.es */ public class SeekBarCustom extends LinearLayout implements OnSeekBarChangeListener { private static final String NS = "http://schemas.android.com/apk/res/android"; private static final String PROGRESS = "progress"; private static final String MAX = "max"; private static final String TEXT = "text"; private int resCode; private SeekBar bar; private TextView caption; public SeekBarCustom(Context context, AttributeSet attrs) { super(context, attrs); this.initUI(attrs); } /** * Inicializamos el control leyendo los atributos personalizados max, progress y text * @param attrs */ private void initUI(AttributeSet attrs){ this.caption = new TextView(this.getContext()); this.bar = new SeekBar(this.getContext()); this.resCode = attrs.getAttributeResourceValue(NS, TEXT, 0); this.setOrientation(LinearLayout.VERTICAL); this.addView(caption); this.addView(bar); int progress = attrs.getAttributeUnsignedIntValue(NS, PROGRESS, 1); caption.setText(getResources().getString(resCode, progress)); bar.setMax(attrs.getAttributeUnsignedIntValue(NS, MAX, 100) + 1); bar.setProgress(progress); bar.setOnSeekBarChangeListener(this); } /** * Permite al usuario establecer el valor, validamos que sea un valor correcto. */ public void setProgress(int p){ if ((p < 0) || (p > bar.getMax())){ throw new IllegalArgumentException(); } bar.setProgress(p); } public int getProgress(){ return bar.getProgress(); } /** * Indica si el usuario ha seleccionado algún valor */ public boolean isValueSelected(){ return (bar.getProgress() > 0); } /** * Cambiamos el título del control cuando el usuario mueve el SeekBar. */ @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { caption.setText(getResources().getString(resCode, progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) {} }
Archivo de recursos de mensajes /res/string.xml
Nota: Si desea traducirlo automáticamente a otros idiomas, puede hacerlo a mano o usar la aplicación toi18n.
Demo: Control Personalizado http://www.carlos-garcia.es Eliga un número del 1 al 10. (Actual %1$d) Aceptar
Conclusiones
Como veis no es difícil crear estos controles y reutilizarlos en un futuro o incluso crearos vuestras propias librerías de componentes..
Espero que os haya sido útil, un saludo.
Carlos García, http://www.carlos-garcia.es.