6.9.8.-
Programación en Android – Actividad Configuración
VIII – Diálogos personalizados
En este capítulo veremos como
crear nuestros propios diálogos personalizados. Existen dos
formas básicas para realizar los diálogos a medida, una
forma consiste en heredar de la clase base Dialog,
y después añadir un layout personalizado, botones en
caso de necesitarlos, etc. Otra de las formas, consiste en utilizar
la subclase AlertDialog,
y en concreto
AlertDialog.Builder,
que nos provee de un mecanismo fácil para crearlo, y es la que
utilizaremos en este primer ejemplo.
Pasos
para crear un diálogo personalizado.
Los
pasos son semejantes a los que tenemos que realizar para crear un
diálogo, y la única diferencia apreciable es que en
este caso debemos de crear un layout a medida que será el
utilizado por el diálogo.
1.-
Tenemos que diseñar un layout personalizado para el diálogo.
2.-
Debemos definir un identificador de diálogo único para
este diálogo.
3.-
Debemos actualizar el método onCreateDialog()
de forma que construya y retorne el objeto de nuestro diálogo
personalizado.
4.-
Debemos lanzar el diálogo con el método showDialog().
Además
nuestro diálogo necesitará nuevos recursos, que
añadiremos antes de comenzar a crear el layout, pero
primeramente veamos como vamos a diseñar nuestro diálogo:
Diseño
del diálogo
Nuestro diálogo necesitará
dos campos de entrada del texto (EditText), uno para la introducción
de la clave y el segundo para volver a introducirla y verificar que
es correcta. Además de ello necesitará los unos
TextView que serán los que pongan los títulos a dichas
cajas de edición.
Veamos como sería el diseño:
|
|
Una vez que tenemos un boceto del
diseño vamos a comenzar a añadir los recursos que
utilizaremos:
Nombre
|
Tipo
|
Valor
|
str_ClavesIguales
|
string
|
Claves
iguales.
|
str_ClavesDistintas
|
string
|
Las
claves son distintas.\nPor favor, vuelva a escribirlas.
|
tl_Clave_Reentrar
|
string
|
Re-entrar
clave:
|
tl_VerClave
|
string
|
Mostrar
clave.
|
color_OK
|
color
|
#0F0
|
Podríamos añadir otras
cadenas, pero como las podemos aprovechar de anteriores recursos pues
entonces simplificamos.
#1
- Creando el layout
A estas alturas no deberíamos
de tener problema para poder crear un nuevo fichero XML en la carpeta
dónde están los layouts, al que llamaremos:
dialogo_poner_clave.xml.
Añadiremos
los siguientes objetos:
Un
linearLayout,
que será la base de nuestro diálogo:
Propiedad
|
Valor
|
Id
|
@+id/LL_DialogoClave
|
Orientation
|
Vertical
|
Layout
height
|
match_parent
|
Layout
width
|
match_parent
|
Después añadiremos un
control TextView:
Propiedad
|
Valor
|
Id
|
@+id/tV_Clave
|
Text
|
@string/tl_Clave
|
Text
Color
|
@color/color_Etiqueta_Configuracion
|
Text
Size
|
@dimen/dim_Etiqueta_Configuracion
|
Layout
height
|
wrap_content
|
Layout
width
|
fill_parent
|
Debajo de este TextView creamos un
EditText:
Propiedad
|
Valor
|
Id
|
@+id/eT_Clave1
|
Input
type
|
textPassword
|
Text
Color
|
@color/color_EditText_Configuracion
|
Max
Lines
|
1
|
Text
Size
|
@dimen/dim_EditText_Configuracion
|
Layout
height
|
wrap_content
|
Layout
width
|
fill_parent
|
Una
vez realizada esta pareja de TextView y EditText, podemos copiar
ambos y pegarlos debajo, y les asignaremos los siguientes valores:
Al
control TextView:
Propiedad
|
Valor
|
Id
|
@+id/tV_Clave_Reentrar
|
Text
|
@string/tl_Clave_Reentrar
|
Text
Color
|
@color/color_Etiqueta_Configuracion
|
Text
Size
|
@dimen/dim_Etiqueta_Configuracion
|
Layout
height
|
wrap_content
|
Layout
width
|
fill_parent
|
Y
al control EditText:
Propiedad
|
Valor
|
Id
|
@+id/eT_Clave2
|
Input
type
|
textPassword
|
Text
Color
|
@color/color_EditText_Configuracion
|
Max
Lines
|
1
|
Text
Size
|
@dimen/dim_EditText_Configuracion
|
Layout
height
|
wrap_content
|
Layout
width
|
fill_parent
|
Después
debemos añadir un último TextView,
que será el que muestre al usuario si las dos claves que ha
introducido coinciden o no:
Propiedad
|
Valor
|
Id
|
@+id/tV_EstadoClave
|
Gravity
|
center_horizontal
|
Text
|
@string/str_ClavesDistintas
|
Text
Color
|
@color/color_Error
|
Text
Size
|
@dimen/dim_Etiqueta_Configuracion
|
Layout
height
|
wrap_content
|
Layout
width
|
wrap_content
|
Layout
gravity
|
center_horizontal
|
Una
vez realizado esto ya podemos comenzar a escribir el código
para nuestro diálogo.
Creando
el código
#2
– Añadir el identificador del diálogo
Procedemos
a añadir a nuestra clase ActividadConfiguración, el
siguiente identificador:
/**Identificador
para el diálogo de la clave */
static
final
int
ID_DIALOGO_CLAVE
= 1;
|
Además,
aprovechamos para crear una variable miembro, que será la que
almacene el valor de la clave para almacenarla posteriormente en el
método onPause().
//Clave
String
mstrClave;
|
#3
– Actualizar el método onCreateDialog
Debemos modificar el método
onCreateDialog para que controlar si es nuestro identificador de
diálogo y actuar en consecuencia. Esto lo hacemos añadiendo
otra sentencia case:
case
ID_DIALOGO_CLAVE:
{//Codigo
aqui}
|
Y
ahora vamos a ver como crear un diálogo personalizado
utilizando la clase AlertDialog.Builder:
//#creamos
un inflater para rellenar nuestro layout
//Vale
cualquiera de las dos maneras:
//LayoutInflater
inflater = (LayoutInflater)
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflater
inflater = (LayoutInflater)
getLayoutInflater();
//Ahora
rellenamos un objeto View con nuestro custom layout
final
View
view_dialogoClave = inflater.inflate(
R.layout.dialogo_poner_clave, (ViewGroup)
findViewById(R.id.LL_DialogoClave));
|
LayoutInflater es
una clase que se utiliza para instanciar el contenido XML a sus
correspondientes objetos view. Nunca
se usa directamente, sino que se utilizan los métodos
getLayoutInflater() o
getSystemService(string)
con los cuales se obtiene una instancia estandar que ya está
enganchada a nuestro contexto actual y configurada actualmente para
nuestro dispositivo.
Después
se utiliza el método inflate()
para llenar la vista con los datos de nuestro fichero XML.
A
partir de aquí ya podemos crear las referencias para acceder a
los controles EditText, accediendo a ellos a través de la View
que acabamos de crear:
//Creamos
referencias para acceder a nuestras EditText:
final
EditText
clave1 = (EditText)
view_dialogoClave
.findViewById(R.id.eT_Clave1);
final
EditText
clave2 = (EditText)
view_dialogoClave
.findViewById(R.id.eT_Clave2);
final
TextView
mensajeEstadoClave = (TextView)
view_dialogoClave.findViewById(R.id.tV_EstadoClave);
|
Ya
podemos comenzar a crear oyentes (listeners) para los eventos de
nuestro diálogo, comenzaremos por añadir un
TextWatcher, que si se añade
a un objeto editable entonces se llamará a sus métodos
cada vez que el texto cambie. Aunque podemos crear una clase
anónima, en este caso he optado por hacerla interna/anidada,
ya que así podemos utilizar este mismo listener para los dos
controles EditText,
además de que personalmente me gusta más así ;)
//Listener
para las EditText de la clave
//
Se añade así para poder añadir este listener
a las dos EditText
class
clave_CambioTextoListener
implements
TextWatcher
{
@Override
public
void
afterTextChanged(Editable
s)
{
//
TODO
Auto-generated method stub
//En
este método debemos comprobar si las claves son iguales:
String
strClave1 = clave1.getText().toString();
String
strClave2 = clave2.getText().toString();
//Ahora
comprobamos si las claves son correctas o no:
if
(strClave1.equals(strClave2))
{
//Si
las claves son iguales:
mensajeEstadoClave.setText(R.string.str_ClavesIguales);
mensajeEstadoClave.setTextColor(res.
getColor(R.color.color_OK));
}
else
{
//Si
las claves son distintas:
mensajeEstadoClave
.setText(R.string.str_ClavesDistintas);
mensajeEstadoClave.setTextColor(res
.getColor(R.color.color_Error));
}
}
@Override
public
void
beforeTextChanged(CharSequence
s, int
start,
int
count, int
after) {
//
TODO
Auto-generated method stub
}
@Override
public
void
onTextChanged(CharSequence
s, int
start,
int
before, int
count)
{
//
TODO
Auto-generated method stub
}
}
|
En
este listener lo que hacemos es verificar si el texto introducido es
igual en ambas EditText, y actualizar el mensaje acorde con ello.
Ahora
enlazamos este listener a los controles:
/**
Creamos el listener para cuando cambie el texto en
*
el EditText de clave2.
*/
clave1.addTextChangedListener(new
clave_CambioTextoListener());
clave2.addTextChangedListener(new
clave_CambioTextoListener());
|
Ahora
cada vez que cambie el texto de cualquiera de estos controles se
llamará a nuestro listener.
Creando
el AlertDialog
Una vez que tenemos los oyentes
(listeners) preparados, ya podemos crear nuestro diálogo:
//Ahora
ya podemos unir nuestra View a un AlertDialog.builder
AlertDialog.Builder
constructor = new
AlertDialog.Builder(this);
constructor.setView(view_dialogoClave);
//Titulo
de nuestro diálogo:
constructor.setTitle(R.string.tl_PonerClave);
|
Después
de construir el constructor,
al utilizar el método setView(),
lo que hacemos es hacer que el contenido de nuestro diálogo
sea lo que hay en dicha View.
Después con setTitle() lo
que hacemos es poner un título a nuestro diálogo.
Añadiendo
el código para los botones
Nuestra vista no tiene botones, y
para que los tenga debemos de crearlos, junto con su respectivo
listener para realizar las acciones pertinentes en caso de pulsarlos.
Vamos a añadir un botón
“negativo”, y con él creamos
anónimamente su oyente:
constructor.setNegativeButton(android.R.string.cancel,
new
DialogInterface.OnClickListener()
{
@Override
public
void
onClick(DialogInterface
dialog,
int
which)
{
//En
caso de pulsar el botón cancelar cerramos el
diálogo ActividadConfiguracion.this.removeDialog(ID_DIALOGO_CLAVE);
}
});
|
Como
vemos, en caso de pulsar este botón quitamos el diálogo
y lo destruimos, para que la próxima vez que vuelva a aparecer
se tenga que reconstruir.
Ahora
veremos el botón “positivo”:
constructor.setPositiveButton(android.R.string.ok,
new
DialogInterface.OnClickListener()
{
@Override
public
void
onClick(DialogInterface
dialog,
int
which)
{
String
strClave1 = clave1.getText().toString();
String
strClave2 = clave2.getText().toString();
//Cogemos
la clave y la almacenamos en la variable miembro:
if
(strClave1.equals(strClave2))
{
//OJO
FIXME
: Podemos guardar aqui:
mstrClave
= strClave1;
TextView
TV_Clave = (TextView)
findViewById(R.id.tV_EstadoClave);
TV_Clave.setTextColor(res .getColor(R.color.color_EditText_Configuracion));
TV_Clave.setText(res .getString(R.string.str_HayClave));
//Eliminamos
el diálogo despues de almacenar la clave.
ActividadConfiguracion.this.removeDialog(ID_DIALOGO_CLAVE);
}
else
{
//
NO GUARDAMOS LA CLAVE NI SALIMOS:
//
ACTUALIZAMOS el TextView por si no lo pone correctamente
//
Si las claves son distintas:
mensajeEstadoClave .setText(R.string.str_ClavesDistintas);
mensajeEstadoClave.setTextColor(res
.getColor(R.color.color_Error));
}
}
});
|
Creo
que el código se explica por si sólo, lo que hacemos es
obtener las cadenas de los controles
edittext y comprobamos si son iguales, en caso de serlo damos la
clave por establecida y almacenamos su valor. En caso contrario pues
seguimos sin clave.
A
partir de aquí sólo nos falta crear el AlertDialog y
retornarlo:
//Creamos
el diálogo:
AlertDialog
dialogoClave = constructor.create();
//Devolvemos
el objeto diálogo:
return
dialogoClave;
|
Realizadas
estas tareas, hemos acabado con el código de onCreateDialog(),
así que ahora tenemos pendiente modificar el método
onPause() para guardar la clave en caso de que exista,
mostrar el diálogo cuando pulsemos el botón
correspondiente, y inicializar el textview cuando se cargan los datos
en inicializaClave().
El
método inicializaClave()
El método quedará de
la siguiente manera, apenas cambia una línea con respecto al
código que ya teníamos escrito:
private
void
inicializaClave()
{
//#3
Cargamos los datos para la Clave.
TextView
TV_Clave = (TextView)
findViewById(R.id.tV_EstadoClave);
if
(mFicheroConfig.contains(PREFERENCIAS_JUEGO_CLAVE))
{
//Ponemos
"Hay clave" en la clave, ya que no vamos
//
a mostrar la clave.
//Y
Cambiamos el color del texto:
TV_Clave.setTextColor(res
.getColor(R.color.color_EditText_Configuracion));
TV_Clave.setText(res.getString(R.string.str_HayClave));
//Guardamos
la clave en la variable miembro:
mstrClave
= mFicheroConfig
.getString(PREFERENCIAS_JUEGO_CLAVE,
null);
}
else
{
//En
caso de que no exista la clave en el fichero:
//
Ponemos el string de No hay clave, y el color de error.
TV_Clave.setText(res.getString(R.string.str_NoHayClave));
TV_Clave.setTextColor(res.getColor(R.color.color_Error));
}
}
|
Mostrar
el diálogo
El método
onClickBoton_PonerClave() debe cambiarse para mostrar el
diálogo, con lo que suprimimos el mensaje toast que
teníamos anteriormente y lo sustituimos por una llamada a
showDialog():
public
void
onClickBoton_PonerClave(View
vista)
{
showDialog(ID_DIALOGO_CLAVE);
}
|
Guardar
los datos
Volvemos a editar el método
onPause() para guardar la clave:
//ATENCIÓN, se ha cambiado lo siguiente:
//ATENCIÓN, se ha cambiado lo siguiente:
//Guardamos
el valor de la clave En caso de ser distinto de null
// if
(!mstrClave.equals(null)) //
if (mstrClave!=null)
{
mEditorFicheroConf.putString(PREFERENCIAS_JUEGO_CLAVE,
mstrClave);
}
|
Creo que no es necesario indicar que
la llamada al método putString debe hacerse antes de
ejecutar el commit() (o el apply()),
de lo contrario no se guardarán los valores.
Y
hasta aquí hemos llegado con el capítulo de hoy. Si
ejecutamos el programa, veremos que al poner la clave, aunque sean
distintas, el diálogo desaparece. Esto ocurre porque hemos
creado nuestro diálogo personalizado a partir de la clase
AlertDialog y utilizando su Builder(). Para evitar que
se oculte la ventana podríamos crear nuestro diálogo
personalizado a partir de la clase base: Dialog. Si lo
hacemos así debemos de crear todo, en el layout deberíamos
de crear los botones, y después crear sus listeners y actuar
en consecuencia. En otro capítulo veremos como modificarlo
para crearlo de esta manera.
Ver.
1.0 – Revisión 30/04/2012
Se debe cambiar dónde pone:
ResponderEliminar//Clave
String mstrClave;
por
//Clave
String mstrClave="";
Ya que si no se inicializa el objeto no se puede acceder al método .equals() posterior y producirá una excepción.
Asimismo también debemos cambiar la comprobación del if, ya que ahora nunca va a ser null.