SlideShare una empresa de Scribd logo
Unidad 2. Diseño de la interfaz de usuario: Vistas y
Layouts
Introducción
El diseño de la interfaz de usuario cobra cada día más importancia en el desarrollo de una
aplicación. La calidad de la interfaz de usuario puede ser uno de los factores que conduzca al
éxito o al fracaso de todo el proyecto.
Si has realizado alguna aplicación utilizando otras plataformas, advertirás que el diseño de la
interfaz de usuario en Android sigue una filosofía muy diferente. En Android la interfaz de
usuario no se diseña en código, sino utilizando un lenguaje de marcado en XML similar al
HTML.
A lo largo de este capítulo mostraremos una serie de ejemplos que te permitirán entender el diseño de la
interfaz de usuario en Android. Aunque no será la forma habitual de trabajar, comenzaremos creando el
interfaz de usuario mediante código. De esta forma comprobaremos como cada uno de los elementos del
interfaz de usuario (las vistas) realmente son objetos Java. Continuaremos mostrando cómo se define el
interfaz de usuario utilizando código XML. Pasaremos luego a ver las herramientas de diseño integradas
en Eclipse. Se describirá el uso de Layouts que nos permitirá una correcta organización de las vistas y
como el uso de recursos alternativos nos permitirá adaptar nuestra interfaz a diferentes circunstancias y
tipos de dispositivos.
En este capítulo también comenzaremos creando la aplicación de ejemplo desarrollada a lo largo del
curso, Asteroides. Crearemos la actividad principal, donde simplemente mostraremos cuatro botones,
con los que se podrán arrancar diferentes actividades. A continuación aprenderemos a crear estilos
y temas y los aplicaremos a estas actividades. Para terminar la unidad propondremos varias
prácticas para aprender a utilizar diferentes tipos de vistas y Layouts.
Objetivos
 Entender cómo se realiza el diseño del interfaz de usuario en una aplicación Android.
 Aprender a trabajar con vistas y mostrar sus atributos más importantes.
 Enumerar los tipos de Layouts que nos permitirán organizar las vistas.
 Mostrar cómo se utilizan los recursos alternativos.
 Aprenderemos a crear estilos y temas para personalizar nuestras aplicaciones.
 Mostrar cómo interactuar con las vistas desde el código Java
 Describir el uso de layouts basados en pestañas (tabs).
Creación de una interfaz de usuario por código
Veamos un primer ejemplo de cómo crear una interfaz de usuario utilizando exclusivamente
código Java. Esta no es la forma recomendable de trabajar con Android, sin embargo resulta
interesante para resaltar algunos conceptos.
Ejercicio paso a paso: Creación del interfaz de usuario por código
1. Abre el proyecto HolaMundo creado en el capítulo anterior y visualiza MainActivity.java.
2. Comenta la última sentencia del método onCreate() añade las tres que se muestran a
continuación en negrita:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
TextView texto = new TextView(this);
texto.setText("Hello, Android");
setContentView(texto);
}
Nota sobre Java: Para poder utilizar el objeto TextView has de importar un nuevo paquete, para
ello añade al principio “import android.widget.TextView;”. Otra alternativa es pulsar Ctrl-Shift-O, para que se
añadan automáticamente los paquetes que faltan.
La interfaz de usuario de Android está basada en una jerarquía de clases descendientes de la
clase View(vista). Una vista es un objeto que se puede dibujar y se utiliza como un elemento
en el diseño de la interfaz de usuario (un botón, una imagen, una etiqueta de texto como en el
utilizado en el ejemplo,…). Cada uno de estos elementos se define como una subclase de la
clase View; la subclase para representar un texto es TextView.
El ejemplo comienza creando un objeto de la clase TextView. El constructor de la clase
acepta como parámetro una instancia de la clase Context (contexto). Un contexto es un
manejador del sistema que proporciona servicios como la resolución de recursos, obtención
de acceso a bases de datos o preferencias. La claseActivity es una subclase de Context, y
como la clase MainActivity es una subclase de Activity, también es tipo Context. Por ello,
puedes pasar this (el objeto actual de la clase MainActivity) como contexto delTextView.
3. Después se define el contenido del texto que se visualizará en
el TextView mediante setText(). Finalmente, mediante setContentView()se indica la vista
utilizada por la actividad.
4. Ejecuta el proyecto para verificar que funciona.
Creación de una interfaz de usuario usando XML
En el ejemplo anterior hemos creado la interfaz de usuario directamente en el código. A veces
puede ser muy complicado programar interfaces de usuario, ya que pequeños cambios en el
diseño pueden corresponder a complicadas modificaciones en el código. Un principio
importante en el diseño de software es que conviene separar todo lo posible el diseño, los
datos y la lógica de la aplicación.
Android proporciona una alternativa para el diseño de interfaces de usuario: los ficheros de
diseño basados en XML. Veamos uno de estos ficheros. Para ello accede al
fichero res/layout/activity_main.xml de nuestro proyecto. Se muestra a continuación. Este
layout o fichero de diseño proporciona un resultado similar que el ejemplo de diseño por código
anterior:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
NOTA: Cuando haces doble clic en el Package Explorer sobre activity_main.xml, probablemente lo
abra en modo Graphical Layout. Para verlo en modo texto selecciona la pestaña activity_main.xml.
Resulta sencillo interpretar su significado. Se introduce un elemento de tipo RelativeLayout,
como se estudiará más adelante su función es contener otros elementos de
tipo View. Este RelativeLayout tiene cinco atributos. Los dos
primeros, xmlns:android,y xmlns:tools son declaraciones de espacios de nombres de
XML que utilizaremos en este fichero (este tipo de parámetro solo es necesario especificarlo
en el primer elemento). Los dos siguientes permiten definir el ancho y alto de la vista. En el
ejemplo se ocupará todo el espacio disponible. El último atributo indica la actividad asociada a
este Layout.
Dentro del RelativeLayout solo tenemos un elemento de tipo TextView. Este dispone de tres
atributos. Los dos primeros definen el ancho y alto (se ajustará al texto contenido). El último
indica el texto a mostrar. No se ha indicado un texto directamente sino una
referencia, "@string/hello_world". Esta referencia ha de estar definida en el
fichero res/values/strings.xml. Si abres este fichero, tienes el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Hola Mundo</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
</resources>
Esta es la práctica recomendada en Android para la inserción de textos en tu aplicación, dado
que facilita su localización a la hora de realizar la traducción a otros idiomas. Es decir,
utilizaremos los ficheros layout para introducir el diseño de los interfaces y el
fichero strings para introducir los textos utilizados en los distintos idiomas.
Ejercicio paso a paso: Creación del Interfaz de usuario con XML
1. Para utilizar el diseño en XML regresa al fichero MainActivity.java y deshaz los cambios que
hicimos antes (elimina las tres últimas líneas y quita el comentario).
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
2. Ejecuta la aplicación y verifica el resultado. Ha de ser muy similar al anterior.
3. Modifica elvalor de hello_world en el fichero res/values/strings.xml.
4. Vuelve a ejecutar la aplicación y visualiza el resultado.
Analicemos ahora la línea en la que acabas de quitar el comentario:
setContentView(R.layout.activity_main) ;
Aquí, R.layout.main corresponde a un objeto View que será creado en tiempo de ejecución a
partir del recurso activity_main.xml. Trabajar de esta forma, en comparación con el diseño
basado en código, no quita velocidad y requiere menos memoria. El plug-in de Eclipse crea
automáticamente este identeficador en la clase R del proyecto a partir de los elementos de la carpeta res.
La definición de la clase R puede ser similar a:
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int ic_launcher=0x7f020000;
}
public static final class id {
public static final int menu_settings=0x7f070000;
}
public static final class layout {
public static final int activity_main=0x7f030000;
}
public static final class menu {
public static final int activity_main=0x7f060000;
}
public static final class string {
public static final int app_name=0x7f040000;
public static final int hello_world=0x7f040001;
...
NOTA: Este fichero se genera automáticamente. Nunca debes editarlo.
Has de tener claro que los identificadores de la clase R son meros números que informan al gestor de
recursos, que datos ha de cargar. Por lo tanto no se trata de verdaderos objetos, estos serán creados en
tiempo de ejecución solo cuando sea necesario usarlos.
Ejercicio paso a paso: El fichero R.java.
1. Abre el fichero llamado gen/com.example.holamundo/R.java de tu aplicación.
2. Comparalo con el fichero mostrado previamente. ¿Qué diferencias
encuentras? (RESPUESTA: los valores numéricos en hexadecimal)
3. Abre el fichero MainActivity.java y reemplaza R.layout.activity_main por el
valor numérico al que corresponde en R.java.
4. Ejecuta de nuevo el proyecto. ¿Funciona? ¿Crees que sería adecuado dejar este
valor numérico?
5. Aunque haya funcionado, este valor puede cambiar en un futuro. Por lo tanto para
evitar problemas futuros vuelve a reemplazarlo por R.layout.activity_main.
Edición visual de las vistas
Veamos ahora como editar los layouts o ficheros de diseño en XML. En el explorador de
paquetes abre el ficherores/layout/ activity_main.xml. Verás que en la parte inferior de la
ventana central aparecen dos lengüetas:Graphical Layout y activity_main.xml. El plug-in de
Android te permite dos tipos de diseño: editar directamente el código XML
(lengüeta activity_main.xml) o realizar este diseño de forma visual
(lengüeta Grafical Layout). (### typo in English text: “Grapical”). Veamos cómo se realizaría el
diseño visual:
En el marco derecho se visualiza una lista con todos los elementos del layout. Este layout tiene solo dos
vistas: un RelativeLayout conteniendo un TextView. En este momento solo hay dos un
RelativeLayoutque contiene un TextView. En el marco central aparece una representación de cómo se
verá el resultado. En la parte superior aparecen varios controles para representar esta vista en diferentes
configuraciones. Cuando diseñamos una vista en Android, hay que tener en cuenta que desconocemos el
dispositivo final donde será visualizada y la configuración específica elegida por el usuario. Por esta
razón, resulta importante que verifiques que la vista se ve de forma adecuada en cualquier configuración.
En la parte superior, de izquierda a derecha, encontramos los siguientes botones: opciones de
previsualización en fase de diseño, tipo de dispositivo (tamaño y resolución de la pantalla), orientación
horizontal (landscape) o vertical (portrait), cómo se verá nuestra vista tras aplicar un tema, la actividad
asociada, la configuración regional (locale), la versión de Android.
Para editar un elemento selecciónalo en el marco de la derecha (Outline) o pincha
directamente sobre él en la ventana de previsualización. Al seleccionarlo puedes modificar
alguna de sus propiedades en el marco Propertiessituado debajo de Outline. Da un vistazo a
las propiedades disponibles para TextView y modifica alguna de ellas. En muchos casos te
aparecerá un desplegable con las opciones disponibles.
El marco de la izquierda te permite insertar de forma rápida nuevas vistas al layout. Puedes
arrastrar cualquier elemento a la ventana de previsualización o al marco Outline. En el anexo B
se ha incluido un listado con las vistas disponibles.
video[Tutorial] Diseño visual de Layouts: Visión general
Ejercicio paso a paso: Creación visual de Vistas
1. Crea un nuevo proyecto con nombre PrimerasVistas. Puedes dejar el resto de parámetros
con los valores por defecto.
2. Abre el fichero res/layout/activity_main.xml.
3. En el marco Outline pulsa con el botón derecho sobre RelativeLayout y selecciona Change
Layout…Selecciona LinearLayout (Vertical). Este tipo de layout es uno de los más sencillos de
utilizar. Te permite representar las vistas una debajo de la otra..
4. Desde la paleta de izquierda arrastra los siguientes elementos: ToggleButton,
CheckBox, ProgressBar(Large)y RatingBar.
5. Selecciona la primera vista que estaba ya creada (TextView) y pulsa el botón <Supr>
para eliminarla.
6. Pulsa el primer botón (Set Horizontal Orientation) para conseguir que
el LinearLayout donde están las diferentes vistas tenga una orientación
horizontal. Comprobarás que no caben todos los elementos.
7. Pulsa el siguiente botón (Set Vertical Orientation) para volver a una orientación vertical.
8. Selecciona la vista ToggleButton. Pulsa el botón siguiente al que acabamos de
utilizar (Toggle Fill Width). Conseguirás que el ancho del botón se ajuste al ancho de su
contenedor.
9. Pulsa el botón siguiente (Troggle Fill Height). Conseguirás que el alto del botón se ajuste
al alto de su contenedor. El problema es que el resto de elementos dejan de verse. Vuelve a
pulsar este botón para regresar a la configuración anterior (También puedes pulsar Ctrl-z).
10. Selecciona la vista CheckBox. Pulsa el botón siguiente al que acabamos de
utilizar(Change Margins…) para introducir un margen en la vista. En la entrada All introduce
“20dp”.
11. Pulsa el botón siguiente(Change Gravity) y selecciona Center Horizontal.
12. Observa como hay un espacio sin usar en la parte inferior del Layout. Pulsa el botón
siguiente(Distribute Weights Evenly). El alto de las vistas se ajustará para que ocupen la
totalidad del Layout. Realmente lo que hace es dividir el espacio sin usar de forma proporcional
entre las vistas. Es equivalente a poner Layout Weights =1 para todas las vistas de este Layout.
Esta propiedad será modificada en un siguiente punto.
13. Con la vista CheckBox selecccionada, pulsa el botón (Assign All Weight) para asignar todo
el alto restante a la vista seleccionada.
14. Pulsa el botón siguiente(Change Layout Weight) e introduce el valor 2. Selecciona la
vistaToggleButton y usando este mismo botón, introduce el valor 0.5. Selecciona la
vista ProgressBar e introduce el valor 4. Como puedes observar estos pesos permiten
repartir el alto sobrante entre las vistas.
15. Utiliza los siguientes botones para ajustar el zoom.
16. Utiliza los botones de la barra superior para observar cómo se representará el Layout en
diferentes situaciones y tipos de dispositivos:
17. Selecciona la vista CheckBox y observa las diferentes propiedades que podemos definir.
Algunas ya han sido definidas por medio de la barra de botones. En concreto y siguiendo el
mismo orden que en los botones hemos modificado: Layout width = wrap_content, Layout height
= wrap_content, Layout margin = 20dp, Layout gravity = center_horizontal y Layout weight = 2.
18. Busca la propiedad Text y sustituye el valor “CheckBox” por “Guardar automáticamente”
y Text size por “9pt”.
19. El resultado final obtenido se muestra a continuación:
Los pequeños triangulos amarillos son advertencias(warnings), donde se nos dan sugerencias para relizar
un diseño correcto. Trata de eliminar alguna de estas advertencias. (Solución: Defir los textos usados
como recursos en res/values/strings.xml y referenciar estos recursos en el
atributoandroid:textcomo: android:text="@string/nombretexto").
20. Pulsa sobre la lengüeta de la parte inferior con nombre activity_main.xml. Pulsa las
teclas Shift-Ctrl-fpara que formatee adecuadamente el código XML. Este código se
muestra a continuación.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<ToggleButton
android:id="@+id/toggleButton1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="ToogleButton" />
<CheckBox
android:id="@+id/checkBox1"
android:layout_width=""wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="2"
android:text="Guardar automáticamente"
android:textSize="9pt" />
<ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="4" />
<RatingBar
android:id="@+id/ratingBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
</LinearLayout>
Observa como el entorno subraya las líneas donde hay advertencias (warnings) en amarillo. Por ejemplo,
nos indica que es preferible introducir los textos como recursos.
21. Ejecuta el proyecto para ver el resultado en el dispositivo.
Ejercicio paso a paso: Vistas de entrada de texto
1. Añade en la parte superior del Layout anterior una vista de tipo entrada de
texto EditText, de tipo normal ( Plain Text). Debajo de esta una de tipo nombre y apellido
(Person Name) seguida de una de tipo palabra secreta (Password). Continua así con
otros tipos de entradas de texto.
2. Ejecuta la aplicación.
3. Observa, como al introducir el texto de una entrada se mostrará un tipo de teclado
diferente.
Los atributos de las vistas
video[Tutorial] Atributo de la clase View en Android
video[Tutorial] Atributo de la clase TexView en Android
Recursos adicionales: Atributos de dimensión
En muchas ocasiones tenemos que indicar el ancho o alto de una vista, un margen, el tamaño
de un texto o unas coordenadas. Este tipo de atributos se conocen como atributos de
dimensión. Dado que nuestra aplicación podrá ejecutarse en gran variedad de dispositivos con
resoluciones muy diversas, Android nos permite indicar estas dimensiones de varias formas.
En la siguiente tabla se muestran las diferentes posibilidades:
px (píxeles): Estas dimensiones representan los píxeles en la pantalla.
mm (milímetros): Distancia real medida sobre la pantalla.
in (pulgadas): Distancia real medida sobre la pantalla.
pt (puntos): Equivale a 1/72 pulgadas.
dp o dip (píxeles independientes de la densidad): Presupone un dispositivo de 160
píxeles por pulgada. Si luego el dispositivo tiene otra densidad, se realizará la
correspondiente regla de tres. Cuando sea representado en dispositivos con una
densidad grafica diferente, este hara un recalculado de forma que se conserve la
misma medida midiendo sobre la pantalla dispositivo. Es decir 160dpequivaldrá
siempre a una pulgada en cualquier tipo de dispositivo. Por lo tanto, se trata de una
medida real sobre pantalla equivalente a 1/160 pulgadas.
sp (píxeles escalados): Similar a dp pero también se escala en función del tamaño
de fuente que el usuario ha escogido en las preferencias. Indicado cuando se
trabaja con fuentes.
Recursos adicionales:Tipos de vista y sus atributos
Consulta el Anexo B del libro para conocer una lista con todos las descendientes de la
clase View y sus atributos.
Layouts
Si queremos combinar varios elementos de tipo vista tendremos que utilizar un objeto de
tipo Layout. Un Layoutes un contenedor de una o más vistas y controla su comportamiento y
posición. Hay que destacar que un Layoutpuede contener a otro Layout y que es un
descendiente de la clase View.
La siguiente lista describe los Layout más utilizados en Android:
LinearLayout: Dispone los elementos en una fila o en una columna.
TableLayout: Distribuye los elementos de forma tabular.
RelativeLayout: Dispone los elementos en relación a otro o al padre.
AbsoluteLayout: Posiciona los elementos de forma absoluta.
FrameLayout: Permite el cambio dinámico de los elementos que contiene.
Dado que un ejemplo vale más que mil palabras, pasemos a mostrar cada uno de
estos layouts en acción:
LinearLayout es uno de los Layout más utilizado en la práctica. Distribuye los elementos uno
detrás de otro, bien de forma horizontal o vertical.
<LinearLayout xmlns:android="http://...
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation ="vertical">
<AnalogClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un checkBox"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un botón"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un texto cualquiera"/>
</LinearLayout>
TableLayoutdistribuye los elementos de forma tabular. Se utiliza la etiqueta TableRowcada
vez que queremos insertar una nueva línea.
<TableLayout xmlns:android=”http://...
android:layout_height="match_parent"
android:layout_width="match_parent">
<TableRow>
<AnalogClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un checkBox"/>
</TableRow>
<TableRow>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un botón"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un texto cualquiera"/>
</TableRow>
</TableLayout>
RelativeLayout permite comenzar a situar los elementos en cualquiera de los cuatro lados del
contenedor e ir añadiendo nuevos elementos pegados a estos.
<RelativeLayout
xmlns:android="http://schemas...
android:layout_height="match_parent"
android:layout_width="match_parent">
<AnalogClock
android:id="@+id/AnalogClock01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"/>
<CheckBox
android:id="@+id/CheckBox01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/AnalogClock01"
android:text="Un checkBox"/>
<Button
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un botón"
android:layout_below="@+id/CheckBox01"/>
<TextView
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Un texto cualquiera"/>
</RelativeLayout>
AbsoluteLayout permite indicar las coordenadas (x,y) donde queremos que se visualice cada
elemento. No es recomendable utilizar este tipo de Layout. La aplicación que estamos diseñando tiene
que visualizarse correctamente en dispositivos con cualquier tamaño de pantalla. Para conseguir esto, no
es una buena idea trabajar con coordenadas absolutas. De hecho, este tipo de Layout ha sido marcado
como obsoleto.
<AbsoluteLayout
xmlns:android="http://schemas.
android:layout_height="match_parent"
android:layout_width="match_parent">
<AnalogClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="50px"
android:layout_y="50px"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un checkBox"
android:layout_x="150px"
android:layout_y="50px"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un botón"
android:layout_x="50px"
android:layout_y="250px"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un texto cualquiera"
android:layout_x="150px"
android:layout_y="200px"/>
</AbsoluteLayout>
FrameLayout posiciona las vistas usando todo el contenedor, sin distribuirlas espacialmente.
Este Layout suele utilizarse cuando queremos que varias vistas ocupen un mismo lugar.
Podemos hacer que solo una sea visible, o superponerlas.Para modificar la visibilidad de un
elemento utilizaremos la propiedad visibility.
<FrameLayout
xmlns:android="http://schemas...
android:layout_height="mach_parent"
android:layout_width="match_parent">
<AnalogClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un checkBox"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un botón"
android:visibility="invisible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un texto cualquiera"
android:visibility="invisible"/>
</FrameLayout>
video[Tutorial] Los Layouts en Android
Recursos adicionales: Propiedades de RelativeLayout
La lista de propiedades específicas de RelativeLayout es muy grande. Te recomendamos que
la consultes en el Anexo B.
Práctica: Uso de Layouts
1. Utiliza un RelativeLayout para realizar un diseño similar al siguiente:
2. Utiliza un TableLayout para realizar un diseño similar al siguiente:
3. Utiliza un AbsoluteLayout para realizar un diseño similar al siguiente.
Ojo AbsoluteLayout lo encontrarás en la paleta Advanced no en la de Layouts. Trata
de reutilizar el Layout creado en el punto anterior.
4. Visualiza el resultado obtenido en el punto anterior en diferentes tamaños de pantalla.
¿Ha sido una buena idea usar AbsoluteLayout? ¿Se te ocurre otra forma de realizar
este diseño de forma que se visualice correctamente en cualquier tipo de pantalla?
5. Trata de hacer el ejercicio anterior utilizando LinearLayout.
6. Visualiza el resultado obtenido en diferentes tamaños de pantalla. ¿Has resuelto el
problema?
Preguntas de repaso y reflexión: Los Layouts
Pincha aquí para hacer un test.
También podemos utilizar otras clases de Layouts, que son descritas a continuación:
ScrollView: Visualiza una columna de elementos; cuando estos no caben en pantalla se
permite un deslizamiento vertical.
HorizontalScrollView: Visualiza una fila de elementos; cuando estos no caben en pantalla se
permite un deslizamiento horizontal.
TabHost: Proporciona una lista de ventanas seleccionables por medio de etiquetas que pueden
ser pulsadas por el usuario para seleccionar la ventana que desea visualizar. Se estudia al
final del capítulo.
ListView: Visualiza una lista deslizable verticalmente de varios elementos. Su utilización es
algo compleja. Se verá un ejemplo en el capítulo siguiente.
GridView: Visualiza una cuadrícula deslizable de varias filas y varias columnas.
ViewFlipper: Permite visualizar una lista de elementos de forma que se visualice uno cada vez.
Puede ser utilizado para intercambiar los elementos cada cierto intervalo de tiempo.
Una aplicación de ejemplo: Mis Lugares
A lo largo de este curso vamos a ir creando una aplicación de ejemplo que toque los aspectos
más significativos de Android. Comenzamos en este capítulo creando una serie de vistas que
nos permitirán diseñar un sencillo interfaz de usuario.
Práctica: Creación de la aplicación Mis Lugares.
1. Crea un nuevo proyecto con los siguientes datos:
Application Name: Mis Lugares
Project Name: MisLugares
Package Name: org.example.mislugares
Minimun Required SDK: API 8: Android 2.2 (Froyo)
Target SDK: API 18
Compile With: API 19: Android 4.4
Activity Name: MainActivity
Layout Name: activity_main
NOTA: Los dos últimos parámetros se introducen en la última ventana.
2. Abre el fichero res/layout/activity_main.xml y trata de crear una vista similar a la que ves a
continuación. Ha de estar formada por un LinearLayout que contiene un TextView y
cuatro Button. Trata de utilizar recursos para introducir los cinco textos que aparecen.
Solución:
1. El fichero activity_main.xml ha de ser similar al siguiente:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="30dp"
tools:context=".MainActivity" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:gravity="center"
android:textSize="25sp "
android:layout_marginBottom="20dp"/>
<Button android:id="@+id/Button01"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_mostrar"/>
<Button android:id="@+id/Button02"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_preferencias"/>
<Button android:id="@+id/Button03"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_acerca_de"/>
<Button android:id="@+id/Button04"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_salir"/>
</LinearLayout>
2. El fichero res/values/strings.xml ha de tener el siguiente contenido:
<resources>
<string name="accion_mostrar">Mostrar Lugares</string>
<string name="accion_preferencias">Preferencias</string>
<string name="accion_acerca_de">Acerca de </string>
<string name="accion_salir">Salir</string>
<string name="app_name">Mis Lugares</string>
<string name="action_settings">Settings </string>
</resources>
Práctica: Un formulario para introducir nuevos lugares
El objetivo de esta práctica es crear un layout que permita introducir y editar lugares en la aplicaciónMis
Lugares.
1. Crea un nuevo layout con nombre edicion_lugar.xml.
2. Ha de parecerse al siguiente formulario. Puedes basarte en un LinearLayout o
un RelativeLayoutpara distribuir los elementos. Pero es importante que este layout, se encuentre dentro
de un ScrollViewpara que cuando el formulario no quepa en pantalla se pueda desplazar verticalmente.
3. Introduce a la derecha del TextView con texto “Tipo:” un Spinner con id tipo. Más adelante
configuraremos esta vista para que muestre un desplegable con los tipos de lugares.
4. Las vistas EditText han de definir el atributo id con los valores: nombre, direccion,
telefono, url y comentario. Utiliza también el atributo hint para dar indicaciones sobre el
valor a introducir. Utiliza el atributo inputType para indicar qué tipo de entrada esperemos. De esta
manera se mostrará un teclado adecuado (por ejemplo si introducimos un correo electrónico aparecerá la
tecla @).
Nota: El atributo inputType admite los siguientes valores (en negrita los que has de gastar en este ejercicio): none,
text, textCapCharacters, textCapWords, textCapSentences, textAutoCorrect, textAutoComplete, textMultiLine,
textImeMultiLine, textNoSuggestions, textUri, textEmailAddress, textEmailSubject. textShortMessage, textLongMessage,
textPersonName, textPostalAddress, textPassword, textVisiblePassword, textWebEditText, textFilter, textPhonetic,
textWebEmailAddress, textWebPassword, number, numberSigned, numberDecimal, numberPassword, phone, datetime,
date y time.
5. Abre la clase MainActivity y reemplaza:
setContentView(R.layout.activity_main);
por
setContentView(R.layout.edicion_lugar);
6. Ejecuta la aplicación y verifica como cambia el tipo de teclado en cada EditText.
Solución:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/t_nombre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nombre:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/nombre"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/t_nombre"
android:hint="algo que identifique el lugar" >
<requestFocus/>
</EditText
<TextView
android:id="@+id/t_tipo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/nombre"
android:text="Tipo:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Spinner
android:id="@+id/tipo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/t_tipo"
android:layout_toRightOf="@id/t_tipo" />
<TextView
android:id="@+id/t_direccion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/t_tipo"
android:text="Dirección:"
android:textAppearance="?android:attr/textAppearanceM
edium" />
<EditText
android:id="@+id/direccion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/t_direccion"
android:hint="dirección del lugar"
android:inputType="textPostalAddress" />
<TextView
android:id="@+id/t_telefono"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/direccion"
android:text="Telefono:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/telefono"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/t_telefono"
android:layout_alignTop="@id/t_telefono"
android:hint="teléfono para contactar"
android:inputType="phone" />
<TextView
android:id="@+id/t_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/telefono"
android:text="Url:"
android:textAppearance="?android:attr/textAppearanceM
edium" />
<EditText
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/t_url"
android:hint="página web"
android:inputType="textUri" />
<TextView
android:id="@+id/t_comentario"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/url"
android:text="Comentario:"
android:textAppearance="?android:attr/textAppearanceM
edium" />
<EditText
android:id="@+id/comentario"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/t_comentario"
android:hint="introduce tus notas"
android:inputType="textMultiLine" />
</RelativeLayout>
</ScrollView>
Una aplicación de ejemplo: Asteroides
A lo largo de este libro vamos a ir creando una aplicación de ejemplo que toque los aspectos más
significativos de Android. Comenzamos en este capítulo creando una serie de vistas que nos permitirán
diseñar un sencillo interfaz de usuario. Si quieres ver cómo quedará la aplicación una vez termines el
libro puedes ver el siguiente vídeo:
video[Tutorial] Asteroides
Enlaces de interés:
Asteroides: Puedes descargarte la aplicación de Google Play
(https://play.google.com/store/apps/details?id=es.upv.asteroides&hl)
Práctica: Creación de la aplicación Asteroides.
1. Crea un nuevo proyecto con los siguientes datos:
Application Name: Asteroides
Project Name: Asteroides
Package Name: org.example.asteroides
Minimun Requiered SDK: API 8: Android 2.2 (Froyo)
Target SDK: API 17: Android 4.2
Compile With: API 17: Android 4.2
Activity Name: Asteroides
Layout Name: main
NOTA: Los dos últimos parámetros se introducen en la última ventana.
2. Abre el fichero res/Layout/main.xml y trata de crear una vista similar a la que ves a
continuación. Ha de estar formada por un LinearLayout que contiene un TexView y
cuatro Button. Trata de utilizar recursos para introducir los cinco textos que aparecen.
Solución:
1. El fichero main.xml ha de ser similar al siguiente:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="30dip"
tools:context=".Asteroides" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/tituloAplicacion"
android:gravity="center"
android:textSize="25sp "
android:layout_marginBottom="20dip"/>
<Button android:id="@+id/Button01"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/Arrancar"/>
<Button android:id="@+id/Button02"
android:layout_height="wrap_content"
android:layout_width="march_parent"
android:text="@string/Configurar"/>
<Button android:id="@+id/Button03"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/Acercade"/>
<Button android:id="@+id/Button04"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/Salir"/>
</LinearLayout>
2. El fichero res/values/strings.xml ha de tener el siguiente contenido:
<resources>
<string name="Arrancar">Jugar</string>
<string name="Configurar">Configurar</string>
<string name="Acercade">Acerca de </string>
<string name="Salir">Salir</string>
<string name="tituloAplicacion">Asteroides</string>
<string name="hello">Hello World, Asteroides! </string>
<string name="app_name">Asteroides</string>
</resources>
Recursos alternativos
Una aplicación Android va a poder ser ejecutada en una gran variedad de dispositivos. El
tamaño de pantalla, la resolución o el tipo de entradas puede variar mucho de un dispositivo a
otro. Por otra parte, nuestra aplicación ha de estar preparada para diferentes modos de
funcionamiento, como el modo automóvil o el modo noche, y para poder ejecutarse en
diferentes idiomas.
A la hora de crear el interfaz de usuario hemos de tener en cuenta todas estas circunstancias.
Afortunadamente la plataforma Android nos proporciona una herramienta de gran potencia
para resolver este problema, el uso de los recursos alternativos.
Práctica: Recursos alternativos en Mis Lugares
1. Ejecuta la aplicación creada en el punto anterior en el emulador.
2. Los teléfonos móviles basados en Android permiten cambiar la configuración en
apaisado y en vertical. Para conseguir este efecto con el emulador pulsa Ctrl+F11. Si,
usando un dispositivo pequeño observas el resultado de la vista que acabas de diseñar
en vertical no queda todo lo bien que desearíamos.
Para resolver este problema Android te permite diseñar una vista diferente para la
configuración horizontal y otra para vertical.
3. Crea la carpeta res/layout-land. Para ello puedes pulsa con el botón derecho sobre la carpeta
res y seleccona New > Folder.
4. Copia en ella el fichero activity_main.xml.Para ello selecciona el fichero y pulsa Ctrl-C.
Selecciona la carpeta destino y pulsa Ctrl-V.
5. Crea una vista similar a la que ves a continuación: formada por un LinearLayout que
contiene un TextView y un TableLayout con dos Button por columna.
6. Ejecuta de nuevo la aplicación y observa como la vista se ve correctamente en las
dos orientaciones.
Solución:
Has de obtener un código XML similar al siguiente:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="30dp"
tools:context=".MainActivity" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:gravity="center"
android:textSize="25sp"
android:layout_marginBottom="20dp"/>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:stretchColumns="*">
<TableRow>
<Button android:id="@+id/Button01"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_mostrar"/>
<Button android:id="@+id/Button02"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_preferencias"/>
</TableRow>
<TableRow>
<Button android:id="@+id/Button03"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_acerca_de"/>
<Button android:id="@+id/Button04"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/accion_salir"/>
</TableRow>
</TableLayout>
</LinearLayout>
NOTA: Para conseguir en un TableLayout, que las columnas se ajusten a todo el ancho de la tabla
poner stretchColumns="*". stretchColumns="0"significa que asigne el ancho sobrante a la primera
columna.stretchColumns="1"significa que asigne el ancho sobrante a la segunda columna.
stretchColumns="*"significa que asigne el ancho sobrante entre todas las columnas.
Android utiliza una lista de sufijos para expresar recursos alternativos. Estos sufijos pueden
hacer referencia a la orientación del dispositivo, al lenguaje, la región, la densidad de píxeles,
la resolución, el método de entrada,…
Por ejemplo, si queremos traducir nuestra aplicación al inglés, español y francés. Siendo el
primer idioma el usado por defecto, crearíamos tres versiones del fichero strings.xml y lo
guardaríamos en los siguientes tres directorios:
res/values/strings.xml
res/values-es/strings.xml
res/values-fr/strings.xml
Ejercicio paso a paso: Traducción de Mis Lugares
1. Crea la carpeta res/values-en.
2. Copia en ella el fichero strings.xml.
3. Traduce en este fichero todas las cadenas al inglés.
4. Ejecuta la aplicación.
5. Vamos a cambiar la configuración de idioma den un dispositivo Android. Para ello,
accede a Ajustes del dispositivo (Settings) y selecciona la opción Mi dispositivo > Idioma e
introducción. Dentro de esta opción selecciona como idioma Español.
NOTA:Observa que en otros idiomas permite seleccionar tanto el idioma como la región.Por
desgracia, para el español solo permite dos regiones España y Estados Unidos.
6. Observa cómo, ahora se ha traducido el texto.
7. ¿Qué pasaría si nuestra aplicación se ejecuta en un terminal configurado en chino?
¿Aparecerán las cadenas en castellano o en inglés? ¿Piensas que esta es una buena decisión de
diseño? ¿Cómo lo podrías solucionar?
Respuestas: Aparecería en castellano. Mala decisión, mejor si aparece en inglés, que es un idioma conocido
universalmente. Habría que poner el fichero strings.xml con los textos en ingles en la caspeta de recurso por
defecto (res/values) y el fichero con los textos en castellano en la carpeta res/values-es.
8. Realiza los cambios propuestos en el punto anterior.
Otro ejemplo de utilización de recursos diferenciados lo podemos ver con el icono que se
utiliza para lanzar la aplicación. Observa como, al crear una aplicación, este icono se crea en
cinco carpetas drawable diferentes, para utilizar un icono distinto según la densidad de píxeles
del dispositivo:
res/drawable-ldpi/ic_launcher.png
res/drawable-mdpi/ic_launcher.png
res/drawable-hdpi/ic_launcher.png
res/drawable-xhdpi/ic_launcher.png
res/drawable-xxhdpi/ic_launcher.png
NOTA:En el siguiente capítulo se describe porque se actua de esta manera..
Resulta posible indicar varios sufijos concatenados; por ejemplo:
res/values-en-rUS/strings.xml
res/values-en-rUK/strings.xml
Pero cuidado, Android establece un orden a la hora de encadenar sufijos. Puedes
encontrar una lista de estos sufijos en el apendice C y en este enlace:
http://developer.android.com/guide/topics/resources/providing-resources.html
Para ver los sufijos disponibles también puedes pulsar con el botón derecho sobre una
carpeta de recursos y seleccionar New > Other… > Android > Android XML File. Esta
opción te permite crear un nuevo fichero XML y poner el sufijo deseado de forma y
orden correcto.
video[Tutorial] Uso de recursos alternativos en Android
Práctica: Creando un Layout para tabletas en Mis Lugares
Si ejecutas la aplicación Asteroides en una tableta observarás que los botones son demasiado
alargados:
1. Trata de hacer un Layout alternativo a main.xml, que sea utilizado en pantallas de
tamaño xlarge (7-10,5 pulgadas) en orientación land (apaisado). Simplemente
poniendo un margen mayor en el Layout se conseguirá unos botones más proporcionados.
2. Si lo deseas también puedes personalizar el fondo de la pantalla
(atributo background), los tamaños de letras, colores, etc.
3. Verifica que la aplicación se visualiza correctamente en todos los tipos de pantalla,
tanto en horizontal como en vertical.
Solución:
1. Crea la carpeta layout-xlarge-land y copia en ella el fichero activity_main.xml.
2. En el nuevo fichero modifica el valor que se usa como margen interno:
<LinearLayout
…
android:padding="150dp"… >
En la siguiente sección trataremos de resolver de una forma más adecuada la asignación de este margen.
3. Ejecuta en un emulador o tableta real de 10 pulgadas y verifica que el resultado:
Tipos de recursos
La definición de los recursos en Android es un aspecto muy importante en el diseño de una
aplicación. Una de sus principales ventajas es que facilita a los diseñadores gráficos e
introductores de contenido trabajar en paralelo con los programadores.
Añadir un recurso a nuestra aplicación es muy sencillo, no tenemos más que añadir un fichero
dentro de una carpeta determinada de nuestro proyecto. Para cada uno de los recursos que
añadamos el sistema crea, de forma automática, un id de recurso dentro de la clase R.
Tipos de recursos
Según la carpeta que utilicemos el recurso creado será de un tipo específico. Pasamos a
enumerar las carpetas y tipos posibles:
carpeta
identificador
Descripción
res/drawable/
R.drawable
Ficheros en bitmap (.png, .jpg o .gif). Ficheros PNG en formato Nine-patch (.9.png).
Ficheros XML con descriptores gráficos (ver clase Drawable)
res/layout/
R.layout
Ficheros XML con los Layouts usados en la aplicación.
res/menu/
R.menu
Ficheros XML con la definición de menús. Podemos asignar una actividad o una vista.
res/anim/
R.anim
Fichero XML que permiten definir una animaciones Tween también conocidas como
animaciones de vista.
res/animator
R.animator
Ficheros XML que permiten modificar las propiedades de un objeto a lo largo del tiempo
Ver sección: animación de propiedades. Solo desde la versión 3.0.
res/xml/
R.xml Otros ficheros XML, como los ficheros de preferencias
res/raw/
R.raw Ficheros que se encuentran en formato binario. Por ejemplo ficheros de audio o vídeo.
res/values/
Ficheros XML que definen un determinado valor para definir un color, estilo, cadena de
caracteres… se describen en la siguiente tabla.
Veamos los tipos de recursos que encontramos dentro de la carpeta values:
fichero por defecto
identificador Descripción
strings.xml
R.string
Identifica cadenas de caracteres
<string name="saludo">¡Hola Mundo!</string>
colors.xml
R.color
Un color definido en formato ARGB (alfa, rojo, verde y azul). Los valores se indica
hexadecimal en uno de los siguientes formatos: #RGB, #ARGB, #RRGGBB ó #A
<color name="verde_opaco">#0f0</color>
<color name="red_translucido">#80ff0000</color>
dimensions.xml
R.dimen
Un número seguido de una unidad de medida.
px - pixeles, mm - milímetros, in – pulgadas, pt – puntos (=1/72 pulgadas), dp – p
independientes de la densidad (=1/160 pulgadas), sp – igual que dp pero cambia
preferencias de tamaño de fuente.
<dimen name="alto">2.2mm</dimen>
<dimen name="tamano_fuente">16sp</dimen>
styles.xml
R.style
Definen una serie de atributos que pueden ser aplicados a una vista o a una activ
aplican a una actividad se conocen como temas.
<style name="TextoGrande"parent="@style/Text">
<item name="android:textSize">20pt</item>
<item name="android:textColor">#000080</item> </style>
R.int
Define un valor entero.
<integer name="max_asteroides">5</integer>
R.bool
Define un valor booleano.
<bool name="misiles_ilimitados">true</bool>
R.id
Define un recurso de ID único. La forma habitual de asignar ID a los recursos es
atributo id="@+id/nombre". Aunque en algunos casos puede ser interesante dis
previamente creados, para que los elementos así nombrados tengan una determ
Este tipo de IDs se utilizan en las vistas TabHost y ListView.
<item type="id" name="button_ok"/>
<item type="id" name="dialog_exit"/>
R.array
Una serie ordenada de elementos. Pueden ser de strings, de enteros o de recurs
(TypedArray)
<string-array name="dias_semana"> < <item>lunes</item>
<item>martes</item>
</string-array>
<integer-array name="primos">
<item>2</item><item>3</item><item>5</item>
</integer-array>
<array name="asteroides"> <item>@drawable/asteroide1</item> <item>@drawabl
</array>
Aunque el sistema crea ficheros que aparecen en la columna de la izquierda de la tabla
anterior y se recomienda definir los recursos de cadena dentro de strings.xml, hay que resaltar
que no es más que una sugerencia de organización. Sería posible mezclar cualquier tipo de
recurso de esta tabla dentro de un mismo fichero y poner a este fichero cualquier nombre.
video[Tutorial] Tipos de recursos en Android
Acceso a los recursos
Una vez definido un recurso este puede ser utilizado desde un fichero XML o desde Java. A
continuación se muestra un ejemplo desde XML:
<ImageView
android:layout_height="@dimen/alto"
android:layout_width="match_parent"
android:background="@drawable/asteroide"
android:text="@string/saludo"
android:text_color="@color/verde_opaco"/>
Para acceder a un recurso definido en los ejemplos anteriores desde Java usaremos el
siguiente código:
Resources res =getResources();
Drawable drawable =res.getDrawable(R.drawable.asteroide);
String saludo = res.getString(R.string.saludo);
int color =res.getColor(R.color.verde_opaco);
float tamanoFuente =res.getDimension(R.dimen.tamano_fuente);
int maxAsteroides =res.getInteger(R.integer.max_asteroides);
boolean ilimitados = res.getBoolean(R.bool.misiles_ilimitados);
String[] diasSemana =res.getStringArray(R.array.dias_semana);
int[] primos =res.getIntArray(R.array.primos);
TypedArray asteroides =res.obtainTypedArray(R.array.asteroides);
Drawable asteroide1 =asteroides.getDrawable(0);
Ejercicio paso a paso: Creando un Layout alternativo con el sufijo -sw
1. Utilizando el editor visual de vistas previsualiza el Layout activity_main.xml modificado en la
práctica anterior.
2. Utiliza el segundo botón de la barra superior para seleccionar una tableta de 10 pulgadas:
3.
Ha de utilizarse el Layout alternativo creado en la práctica.
4. Selecciona ahora una tableta de 7 pulgadas. Observa como ya no se utilizará este Layout. La razón
es que este una tableta de 7 pulgadas se considera de tamaño large y no xlarge. Si quisiéramos
aplicar también este Layout para este tamaño, tendríamos que crear una nueva carpeta con sufijo -
large y copiar el Layout dentro. Copiar el mismo recurso dos veces no parece muy razonable.
5. Para ajustar nuestros diseños a los tamaños de pantalla en el Nivel de API 13 se introduce una
alternativa más práctica: el sufijo -sw o ancho menor:
Veamos cómo se utiliza. Primero se obtiene el menor entre ancho y alto de pantalla disponible y se
compara el valor indicado en la carpeta. Solo se cargará el recurso si el valor obtenido es mayor al
indicado en la carpeta. Si varias carpetas cumplen la condición se usa la carpeta con mayor valor. Es
obligatorio utilizar dp como unidad (1dp=1/160 pulgadas). Este valor no se calcula con el ancho total de
la pantalla física, si no con el espacio disponible para la aplicación. Los elementos permanentes del IU
del sistema (como botones en pantalla) no se cuentan como espacio disponible.
El uso habitual es para indicar en ancho mínimo que soporta un layout. Hay que recordar que se compara
con el mínimo entre ancho y alto, por lo tanto, no afecta cambiar la inclinación de horizontal a vertical.
Los valores típicos que se utilizan se muestran a continuación:
sw320dp = 2’ = 50mm (móvil pequeño)
sw480dp = 3’ = 76mm (móvil grande)
sw600dp = 3,75’= 95mm (tableta 7’)
sw720dp = 4,5’ = 114mm (tableta 10’)
6. Crea la carpeta layout-sw600dp-land y copia en ella el fichero activity_main.xml de la
carpetalayout-xlarge-land.
7. Elimina la carpeta layout-xlarge-land.
8. Verifica que este Layout es utilizado tanto en carpetas de 7 y 10 pulgadas.
Nota: El sufijo –sw aparece en el nivel de API 13 (v3.2). Esto significa que cuando esta aplicación sea cargada en un
dispositivo con una versión anterior a la 3.2 la carpeta que acabamos de crear será ignorada. Esta circunstancia podrá
darse dado que, el nivel mínimo de API seleccionado en Mis Lugares es 8 (v2.2).
Ejercicio paso a paso: Uso de dimensiones en recursos alternativos
Crear un nuevo recurso de Layout simplemente para cambiar los márgenes no es una buena idea. Si más
adelante decidimos modificarlo, por ejemplo añadiendo un gráfico, tendremos que modificar cada uno
de los Layouts creados. Cuando lo que quieras ajustar sea un tamaño (margen, tamaño de letra, ancho,
alto, etc.), lo más recomendable es definir un recurso de dimensión y definirlo según el tamaño
disponible. Este ejercicio ilustra cómo hacerlo.
1. En el explorador de paquetes busca el proyecto HolaMundo. Expande la capeta res. Observa como al
crear un nuevo proyecto se ha creado el fichero dimens.xml en tres carpetas diferentes:
2. Abre el fichero dimens.xml en su versión por defecto (res/values/dimens.xml). Se mostrará:
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
3. Abre el fichero res/values-sw600dp/dimens.xml. Observa como no se incluye ninguna dimensión.
Se ha creado para facilitarte la adaptación de los diseños de layout en pantallas de 7 pulgadas o más.
4. Abre el fichero res/values-sw720dp-land/dimens.xml. Se mostrará:
<resources>
<!-- Customize dimensions originally defined in res/values/dimens.xml
(such as screen margins) for sw720dp devices (e.g. 10" tablets) in
landscape here.-->
<dimen name="activity_horizontal_margin">128dp</dimen>
</resources>
5. Tras analizar estos tres ficheros, puedes decir que posibles valores tomarán las dos dimensiones
definidas y cuando.
Solición: activity_vertical_margin siempre valdrá 16dp
y activity_horizontal_margin valdrá 128dp cuando estemos en una pantalla de más de 10 pulgadas
en posición horizontal y en el resto de los casos 16dp.
6. Abre el fichero res/layout/activity_main.xml. Se mostrará:
<RelativeLayout
…
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
… >
Obserba como se están utilizando las dimensiones definidas para indicar los márgenes inferior,
izquierdo, derecho y superior.
7. Vamos a aplicar esta filosofía de trabajo a la aplicación Mis Lugares.
8. Abre el fichero MisLugares/res/layout/activity_main.xml. Reemplaza:
<LinearLayout
…
android:padding="30dp"
… >
Por:
<RelativeLayout
…
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
… >
9. Reemplaza:
<TextView
…
android:textSize="25sp"/>
por:
<TextView
…
android:textSize="@dimen/titulo" />
10. Añade a cada uno de los cuatro botones el atributo textSize de la siguiente manera:
<Button
…
android:textSize="@dimen/boton"/>
11. Realiza los cambios de los tres últimos puntos, pero ahora en el fichero res/layout-
land/activity_main.xml.
12. Edita el fichero res/dimens.xml para obtener:
<resources>
<dimen name="activity_horizontal_margin">25dp</dimen>
<dimen name="activity_vertical_margin">25dp</dimen>
<dimen name="titulo">25sp</dimen>
<dimen name="boton">16sp</dimen>
</resources>
13. Edita el fichero res/values-sw600dp/dimens.xml para obtener:
<resources>
<dimen name="activity_horizontal_margin">75dp</dimen>
<dimen name="titulo">35sp</dimen>
<dimen name="boton">22sp</dimen>
</resources>
14. Edita el fichero res/values-sw720dp-land/dimens.xml para obtener:
<resources>
<dimen name="activity_horizontal_margin">150dp</dimen>
<dimen name="titulo">45sp</dimen>
<dimen name="boton">30sp</dimen>
</resources>
15. Tras la definiciones introducida ¿Qué valor tomará activity_horizontal_margin, cuando
se ejecute la aplicación en una tableta de 110 pulgadas.
Solución: Depende de su posición: en horizontal 150dp y en vertical 75 dp.
16. Borra la carpeta res/layout-sw600dp-land con su contenido. Ya no necesitamos esta layout.
17. Para verificar los resultados no es necesario disponer de tabletas de diferentes tamaños, ni siquiera
crear diferentes emuladores. Puedes abrir la edición visual del layout activity_main y previsualizar en
diferentes tamaños de pantalla y orientación. Es recomendable para esta prueba que tengas seleccionado
en ajuste de zum, para que se ajuste al tamaño real:
Recursos del sistema
Además de los recursos que podamos añadir a nuestra aplicación, también podemos utilizar
una serie de recursos que han sido incluidos en el sistema.
video[Tutorial] Recursos del sistema en Android
Usar recursos del sistema tiene muchas ventajas. No consumen memoria en nuestra
aplicación, al estar ya incorporados al sistema. Además los usuarios están familiarizados con
ellos. Por ejemplo, si utilizamos el recursoandroid.R.drawable.ic_menu_edit se
mostrará al usuario el icono: . Muy posiblemente el usuario ya está familiarizado con este
icono y lo asocie a la acción de editar. Otra ventaja es que los recursos del sistema se
adaptan a las diferentes versiones de Android. Si se utiliza el
tema android.R.style.Theme_Panel este es bastante diferente en cada una de las
versiones, pero seguro que estará en consonancia con el resto de estilos para esta versión. Lo
mismo ocurre con el icono anterior. Este icono es diferente en algunas versiones, pero al usar
un recurso del sistema nos aseguramos que se mostrará el adecuado a la versión del usuario.
Finalmente, estos recursos se adaptan siempre a las configuraciones locales. Si yo utilizo el
recursoandroid.R.string.cancel este será “Cancelar”, “Cancel”, “取消”,... según el
idioma escogido por el usuario.
Obtener una lista con los recursos del sistema disponible no es sencillo. Te
recomendamos que instales la aplicación Android.R en cualquier dispositivo para explorar los
recursos del sistema.
Para acceder a los recursos del sistema desde código usaremos la clase android.R. Se
utiliza la misma estructura de jerárquica de clases. Por
ejemplo android.R.drawable.ic_menu_edit. Para acceder desde XML utiliza la sintaxis
habitual pero comenzando con @android:. Por ejemplo @android:drawable/ic_menu_edit.
Estilos y temas
Si tienes experiencia con el diseño de páginas Web habrás advertido grandes similitudes entre
HTML y el diseño de Layouts. En los dos casos se utiliza un lenguaje de marcado y se trata de
crear diseños independientes del tamaño de la pantalla donde serán visualizados. En el
diseño web resulta clave las hojas de estilo en cascada (CSS) que permiten crear un patrón
de diseño y aplicarlo a varias páginas. Cuando diseñes los Layouts de tu aplicación vas a
poder utilizar unas herramientas similares conocidas como estilos y temas. Te permitirán crear
patrones de estilo que podrán ser utilizados en cualquier parte de la aplicación. Estas
herramientas te ahorrarán mucho trabajo y te permitirán conseguir un diseño homogéneo en
toda tu aplicación.
video[Tutorial] Estilos y Temas en Android
Los estilos
Un estilo es una colección de propiedades que definen el formato y apariencia que tendrá una
vista. Podemos especificar cosas como tamaño, márgenes, color, fuentes, etc. Un estilo se
define en ficheros XML, diferente al fichero XML Layout que lo utiliza.
Veamos un ejemplo. El siguiente código:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#00FF00"
android:typeface="monospace"
android:text="Un texto" />
Es equivalente a escribir:
<TextView
style="@style/MiEstilo"
android:text="Un texto" />
Habiendo creado en el fichero res/values/styles.xml conel siguiente código:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<stylename="MiEstilo"
parent="@android:style/TextAppearance.Medium">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#00FF00</item>
<item name="android:typeface">monospace</item>
</style>
</resources>
Observa como un estilo puede heredar todas las propiedades de un padre (parámetro parent) y a partir de
estas propiedades realizar modificaciones.
Heredar de un estilo propio
Si vas a heredar de un estilo definido por ti no es necesario utilizar el atributo parent. Por el
contrario, puedes utilizar el mismo nombre de un estilo ya creado y completar el nombre con
un punto más un sufijo.Por ejemplo:
<stylename="MiEstilo.grande">
<item name="android:textSize">18pt</item>
</style>
Crearía un nuevo estilo que sería igual a MiEstilo más la nueva propiedad indicada. A su vez puedes
definir otro estilo a partir de este:
<stylename="MiEstilo.grande.negrita">
<item name="android:textStyle">bold</item>
</style>
Práctica: Creando un estilo
1. Abre el proyecto Asteroides o Mis Lugares (dependiendo del curso).
2. Crea un nuevo estilo con nombre EstiloTexto.
3. Aplícalo al título que aparece en el Layout activity_ main.xml
4. Crea un nuevo estilo con nombre EstiloTexto.Botones. Este ha de modificar
alguno de los atributos anteriores y añadir otros, como padding.
5. Aplícalo a todos los botones del Layout.
6. Visualiza el resultado.
Los temas
Un tema es un estilo aplicado a toda una actividad o aplicación, en lugar de a una vista
individual. Cada elemento del estilo solo se aplicará a aquellos elementos donde sea posible.
Por ejemplo, CodeFont solo afectará al texto.
Para aplicar un tema a toda una aplicación edita el fichero AndroidManifest.xml y añade el
parámetroandroid:theme en la etiqueta application:
<application android:theme="@style/MiTema">
También puedes aplicar un tema a una actividad en concreto:
<activity android:theme="@style/MiTema">
Además de crear tus propios temas vas a poder utilizar algunos disponibles en el sistema. Puedes
encontrar una lista de todos los estilos y temas disponibles en Android
en:http://developer.android.com/reference/android/R.style.html
Ejercicio paso a paso: Aplicando un tema del sistema
1. Abre el proyecto Asteroides o Mis Lugares (dependiendo del curso).
2. Aplica a la actividad principal el tema android:style/Theme.Dialog tal y como
se acaba de mostrar.
3. Visualiza el resultado.
Práctica: Creando un tema
1. Abre el proyecto Asteroides o Mis Lugares (dependiendo del curso).
2. Crea un tema con nombre TemaAsteroides que herede
de android:style/Theme.NoTitleBar. Este tema no muestra la barra con el
nombre de la aplicación.
3. Aplica este tema a la aplicación.
Uso práctico de Vistas y Layouts
En este apartado vamos a aprender a usar varios tipos de vistas y Layouts desde un punto de
vista práctico. También empezaremos a escribir código que será ejecutado cuando ocurran
ciertos eventos:
Ejercicio paso a paso: Un botón con gráficos personalizados
1. Crea un nuevo proyecto con los siguientes datos:
Application name: MasVistas
Package name: org.example.masvistas
Minimun Requiered SDK: API 7 Android 2.1 (Eclair)
Activity Name: MasVistasActivity
Layout Name: main.xml
2. Crea el fichero boton.xml en la carpeta res/drawable/. Para ello puedes utilizar el
menúArchivo/Nuevo/Android XML File y pon en File: “botón” y selecciona en tipo Drawable.
Reemplaza el código por el siguiente:
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/boton_pulsado"
android:state_pressed="true" />
<item android:drawable="@drawable/boton_con_foco"
android:state_focused="true" />
<item android:drawable="@drawable/boton_normal" />
</selector>
Este XML define un recurso único gráfico (drawable) que cambiará en función del estado del
botón. El primer <item> define la imagen usada cuando se pulsa el botón, el segundo <item>
define la imagen usada cuando el botón tiene el foco (cuando el botón está seleccionado con la
rueda de desplazamiento o las teclas de dirección), el tercero la imagen en estado normal. Los
gráficos y en concreto los drawables serán estudiados en el CAPÍTULO 1 y CAPÍTULO 4.
NOTA: El orden de los elementos <item> es importante. Cuando se va a dibujar se recorren los ítems
en orden hasta que se cumpla una condición. Debido a que "boton_normal" es el último, sólo se aplica
cuando las condicionesstate_pressedy state_focused no se cumplen.
3. Descarga las tres imágenes que aparecen a continuación de www.androidcurso.com. El
nombre que ha de tener cada fichero aparece debajo:
boton_normal.jpg boton_con_foco.jpg boton_pulsado.jpg
4. Arrastra estas imágenes a la carpeta res/drawable/ del proyecto.
5. Abre el fichero res/layout/main.xml.
6. Elimina el TextView que encontrarás dentro del LinearLayout.
7. Selecciona el LinerLayout e introduce en el atributo Background el valor #FFFFFF.
8. Arrastra una vista de tipo Button dentro del LinearLayout.
9. Selecciona el atributo Background y pulsa en el botón selector de recurso (con puntos
suspensivos). Selecciona Drawable/boton.
10. Modifica el atributo Text para que no tenga ningún valor.
11. Introduce en el atributo onClick el valor sePulsa. (Ojo; este atributo solo está disponible a
partir de la versión 1.6)
12. Abre el fichero MasVistasActivity.java e introduce al final, antes de la última llave, el
código:
public void sePulsa(View view){
Toast.makeText(this, "Pulsado", Toast.LENGTH_SHORT).show(); }
Pulsa Ctrl-Shift-O para que se añadan automáticamente los paquetes que faltan en la
sección import.
El método anterior será ejecutado cuando se pulse el botón. Este método se limita a lanzar
un Toast, es decir, un aviso que permanece un cierto tiempo sobre la pantalla y luego
desaparece. Los tres parámetros son: 1-El contexto utilizado, coincide con la actividad.
2-El texto a mostrar y 3-El tiempo que permanecerá este texto. Los conceptos
de actividad y contexto serán desarrollados en el siguiente capítulo.
13. Ejecuta el proyecto y verifica el resultado.
14. El código resultante para el fichero main.xml se muestra a continuación:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">
<Button android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/boton"
android:onClick="sePulsa"/>
</LinearLayout>
Acceder y modificar las propiedades de las vistas por código
Ejercicio paso a paso: Acceder y modificar las propiedades de las vistas por
código
1. Abre el Layout main.xml creado en el ejercicio anterior.
2. En la paleta de vistas, dentro de Text Fields, busca Number (Decimal) y arrástralo encima del botón rojo.
3. Modifica algunos atributos de esta vista: Hint = “Introduce un número”, id = “@+id/entrada”
4. En la paleta de vistas, dentro de Form Widgets, busca Button y arrástralo encima del botón rojo.
5. Modifica algunos atributos de esta vista: Haz que su ancho ocupe toda la pantalla, que su texto sea “0”.
6. En la paleta de vistas, dentro de Form Widgets, busca Large Text y arrástralo debajo del botón rojo.
7. Modifica algunos atributos de esta vista: TextColor = #0000FF, Text = “”, Hint = “Resultado”, id=
“@+id/salida”.
8. Abre el fichero MasVistaActivity.java. Vamos a añadir dos nuevas propiedades a la clase. Para ello copia el
siguiente código al principio de la clase (antes del método onCreate):
private EditText entrada;
private TextView salida;
9. Copia al final del método onCreate las siguientes dos líneas:
entrada = (EditText) findViewById(R.id.entrada);
salida = (TextView) findViewById(R.id.salida);
10. Como se explicó al principio del capítulo, las diferentes vistas definidas en main.xml, son creadas como
objetos Java cuando se ejecuta setContentView(R.layout.main). Si queremos manipular algunos
de estos objetos hemos de declararlos (paso 8) y asignarles el objeto correspondiente. Para ello, hay que
introducir el atributo id en xml y utilizar el métodofindViewById(R.id.valor_en_atributo_id).
Este método devuelve un objeto de la claseView, no obstante los objetos declarados (entrada y salida)
no son exactamente de esta clase por lo que Java no permite una asignación directa. En estos casos hemos de
utilizar una conversión de tipo (type cast) para poder hacer la asignación. Para más información al respecto
leer el apartadoPolimorfismo del tutorial de Java Esencial.
11. Introduce en el atributo onClick del botón con id boton0 el valor “sePulsa0”.
12. Añade el siguiente método al final de la clase MasVistasActivity.
public void sePulsa0(View view){
entrada.setText(entrada.getText()+"0");
}
13. Añade al botón con texto “0” el atributo tag = “0”.
14. Modifica el método sePulsa0 de la siguiente forma:
public void sePulsa0(View view){
entrada.setText(entrada.getText()+(String)view.getTag());
}
El resultado obtenido es equivalente al anterior. En algunos casos será interesante utilizar un mismo método
como escuchadorde eventos de varias vistas.Podrás averiguar la vista que causó el evento,dado que esta es
pasada como parámetro del método. En el ejemplo sabemos que en el atributo tagguardamos el carácter a
insertar. El atributo tag puede serusado libremente por el programador para almacenar un objeto de la
clase Object (mas info ). En nuestro caso hemos almacenado un objetoString, por lo que necesitamos una
conversión de tipo. Otro ejemplo de Polimorfismo. NOTA: Utiliza esta forma de trabajar en la práctica para
no tener que crear un método onClick para cada botón de la calculadora.
15. Modifica el código de sePulsa con el siguiente código:
public void sePulsa(View view){
salida.setText(String.valueOf(
Float.parseFloat(entrada.getText().toString())*2.0));
}
En este código el valor de entrada es convertido en Float, multiplicado por dos y convertido en String para
ser asignado a salida.
16. Ejecuta el proyecto y verifica el resultado.
Uso de TabHost
La vista TabHost nos va a permitir crear un interfaz de usuario basado en pestañas. Este
permite de una forma muy intuitiva ofrecer al usuario diferentes vistas, sin más que
seleccionar una de las pestaañas que se muestran en la parte superior:
Para crear una interfaz de usuario con pestañas, es necesario
utilizar FragmentTabHost y TabWidget. ElFragmentTabHost debe ser el nodo raíz para
el diseño, que contendrá tanto el TabWidget para la visualización de las pestañas,
como un FrameLayout para mostrar el contenido. A continuación se muestra el esquema a
utilizar:
Nota: En las primeras versiones de Android se usaba TabHost en lugar FragmentTabHost. A partir del
nivel de API 13, TabHost ha sido declarado como obsoleto. Google ha reorientado su gerarquia de
clases para introducir el concepto de fragments. No obstante, puedes seguir utilizando TabHost sin
ningún problema.
Nota: Hasta la vesión 3.0 (API 11) no aparece FragmentTabHost. Entonces, no podría usarse en niveles
de API anteriores. Para resolver este problema, y más generalmente para poder usar fragments en
versiones anteriores a la 3.0, Google ha creado la librería de compatibilidad[1] (android.support).. Es
añadida por defecto al crear un nuevo proyecto. Poe lo tanto, podemos usar Fragments y clases
relacionadas desde versiones
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost" …/>
<LinearLayout …>
<TabWidget
android:id="@android:id/tabs" …/>
<FrameLayout
android:id="@android:id/tabcontent" …>
<PrimerLayout … />
<SegundoLayout … />
<TercerLayout … />
…
</FrameLayout>
</LinearLayout>
</TabHost>
[1]http://developer.android.com/tools/extras/support-library.html
Puedes implementar el contenido de dos maneras: usando las pestañas para intercambiar puntos de vista
dentro de la misma actividad, o puedes utilizar las pestañas para cambiar entre actividades totalmente
independientes.
En este apartado, vamos a crear una interfaz de usuario con pestañas que utiliza una única actividad.
Para hacerlo con diferentes actividades para cada pestaña puedes seguir el tutorial:
Nota: El siguiente vídeo utiliza TabHost en lugar FragmentTabHost. No obstante, los conceptos que se
explican siguen siendo válidos.
Puedes ver algunos aspectos relacionados en
formato poli[Media]
La vistaTabHost en Android
Ejercicio paso a paso: Uso de TabHost
1. Crea un nuevo proyecto con los siguientes datos
Application name: TabHost
Package name: org.example.tabhost
Minimun Requiered SDK: API 7 Android 2.1 (Eclair)
Activity Name: TabHostActivity
Layout Name: activity_main.xml
2. Reemplaza el código de activity_main.xml por el siguiente:
<android.support.v4.app.FragmentTabHostxmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/tab1"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="esto es una pestaña" />
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
</LinearLayout>
<TextView
android:id="@+id/tab2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="esto es otra pestaña" />
<TextView android:id="@+id/tab3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="esto es la tercera pestaña" />
</FrameLayout>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
Como puedes observarse ha creado un FragmentTabHost debe ser el nodo raíz para el diseño, que
contiene dos elementos combinados por medio de un LinearLayout. El primero es un TabWidget para la
visualización de las pestañas y el segundo es un FrameLayout para mostrar el contenido de la
ficha. Dentro de este FrameLayout hay tres elementos, cada uno de los cuales contendrá las vistas a
mostrar para cada una de las lengüetas.Tienes que tener especial cuidado con los atributos id.
El FragmentTabHost debe llamarse siempre "@android:id/tabhost", mientras que elTabWidget ha
de llamarse "@android:id/tabs". De esta forma el sistema conocerá la finalidad de cada uno de
estos elementos. Por otra parte, cada una de las vistas de contenido introducidas dentro
del FrameLayout han de tener un id asignado por ti, como "@+id/tab1".
3. Para que un FragmentTabHost funcione resulta imprescindible introducir el siguiente código.
Abre el ficheroMainActivity.java y reemplaza el código por el siguiente.
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TabHost tabHost = getTabHost();
tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator(
"Título 1", null).setContent(R.id.tab1Layout));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator(
"Título 2", null).setContent(R.id.tab2Layout));
tabHost.addTab(tabHost.newTabSpec("tab3").setIndicator(
"Título 3", null).setContent(R.id.tab3Layout));
}
}
Observa como la clase creada extiende de TabActivity en lugar de Activity.Además, se han añadido
varias líneas al final del método onCreate(). La primera línea obtiene la actividad que muestra las
pestañas mediante getTabHost().Luego añadimos tantas pestañas como nos interese. Para cada una se
crea indicando un tag (newTabSpec()), se le asocia un título y un icono (setIndicator()) y se indica donde
está el contenido (setContent()). NOTA: Los iconos disponibles en el sistema y cómo crear nuevos
icono será estudiado en el siguiente capítulo.
4. Ejecuta el proyecto y verifica el resultado.
Uso de la etiqueta <include> en Layouts
Un diseño basado en TabHost puede requerir ficheros xml muy extensos. Para organizar
correctamente el trabajo y reutilizar diseños previos puede ser de gran ayuda la etiqueta <include>
Ejercicio paso a paso: Uso de la etiqueta <include> en Layouts
1. Empezaremos realizando una copia del
fichero MasVistas/res/layout/main.xml aTabLayout/res/layout/boton_rojo.xml. Para ello selecciona el
primer fichero y pégalo en la carpeta MasVistas/res/layout. Te pedirá un nuevo nombre
escribe boton_rojo.xml. Arrastra el nuevo fichero hasta la carpeta TabLayout/res/layout.
2. Realiza el mismo proceso con uno de los Layout creado en la práctica Uso de Layouts, donde se diseñaba
el teclado de una calculadora. En nuestro proyecto ha de llamarse calculadora.xml
3. Realiza el mismo proceso con el Layout creado en el ejercicio paso a paso Creación visual de vistas. En
nuestro proyecto ha de llamarse primer_layout.xml.
4.Añade el atributo android:id="@+id/tab1Layout" en el LineraLayout raíz de botón_rojo.xml. Añade el
atributo android:id="@+id/tab2Layout" en calculadora.xml y "@+id/tab3Layout" en primer_la
yout.xml.
5. Abre el fichero main.xml y reemplaza el FrameLayout por:
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/boton_rojo"/>
<include layout="@layout/calculadora"/>
<include layout="@layout/primer_layout"/>
</FrameLayout>
6. Ejecuta el proyecto y verifica el resultado. Ojo: si pulsas alguno de los botones es posible que no funcione.
Recuerda que no hemos copiado el código.
Has podido comprobar cómo hemos conseguido un diseño muy complejo sin la necesidad de crear un xml
demasiado grande. De esta forma, tenemos el código xml separado en cuatro ficheros diferentes. Además
ha sido muy sencillo reutilizar diseños previos.
Uso de FragmentTabHost
A partir del nivel de API 13, TabHost ha sido declarado como obsoleto. Google ha reorientado
su jerarquía de clases para introducir el concepto de fragment, de manera que en lugar
de TabHost, propone utilizarFragmentTabHost. No obstante, podemos seguir
utilizando TabHost sin ningún problema.
La clase FragmentTabHost no aparece hasta la versión 3.0 (API 11). Entonces, no podría
usarse en niveles de API anteriores. Para resolver este problema, y más generalmente para
poder usar fragments en versiones anteriores a la 3.0, Google ha creado una librería de
compatibilidad[1] (android.support). Es añadida por defecto al crear un nuevo proyecto.
Gracias a esta librería, podemos usar fragments y clases relacionadas en todas las versiones.
[1]http://developer.android.com/tools/extras/support-library.html
Ejercicio paso a paso: Uso de FragmentTabHost
1. Crea un nuevo proyecto con los siguientes datos
Application name: FragmentTabHost
Package name: org.example.fragmenttabhost
Minimun Requiered SDK: API 8 Android 2.2 (Froyo)
2. Reemplaza el código de activity_main.xml por el siguiente:
<android.support.v4.app.FragmentTabHostxmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mi_tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"/>
<FrameLayout
android:id="@+id/contenido"
android:layout_width="match_parent"
android:layout_height="0dp"/>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
Como puedes observar se ha creado un FragmentTabHost, que contiene dos elementos combinados por medio de
un LinearLayout. El primero es un TabWidget para la visualización de las pestañas y el segundo es
un FrameLayout paramostrar el contenido asociado de cada lengüeta. En número de lengüetas y su contenido se
indicará por código. Observa los valores con los atributos id. El TabWidget se ha
utilizado "@android:id/tabs", un identificador fijo definido como recurso del sistema. De esta
forma estamos indicando la finalidad que tiene. Para el resto de elementos se han definido nuevos
identificadores
3. Abre el fichero MainActivity.java y reemplaza el código por el siguiente:
package com.example.fragmenttabhost;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
public class MainActivity extends FragmentActivity {
private FragmentTabHost tabHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabHost = (FragmentTabHost) findViewById(R.id.mi_tabhost);
tabHost.setup(this, getSupportFragmentManager(), R.id.contenido);
tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("Lengüeta 1"),
Tab1.class, null);
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("Lengüeta 2"),
Tab2.class, null);
tabHost.addTab(tabHost.newTabSpec("tab3").setIndicator("Lengüeta 3"),
Tab3.class, null);
}
}
Observa como la clase creada extiende de FragmentActivity en lugar de Activity.
Esto permitirá que la actividad trabaje con Fragments, en concreto, vamos a crear
un fragmnet para cada lengüeta. Se han añadido varias líneas en el método onCreate().
Empezamos inicializando la variable tabHost, luego se utiliza el método setup() para
configurarla. Para ello indicamos el contexto, manejador de fragments y donde se
mostrarán los fragments.
Cada una de las siguientes tres líneas introduce una nueva lengüeta usando el
método addTab().Se indican tres parámetros: Un objeto TabSpec, una clase con
el Fragment a visualizar en la lengüeta y un Bundle por si queremos pasar información a
la lengüeta. El método newTabSpec()crear una nueva lengüeta en un TabHost. Se le
pasa como parámetro un String que se utiliza como identificador y devuelve el objeto
de tipo TabSpec creado.
Nota sobre Java: Dado que el método newTabSpec() devuelve un objeto de tipo TabSpec,
tras la llamada podemos llamar al método setIndicator()que nos permitirá introducir un descriptos en la
pestaña recién creada.
NOTA:También podremos asignar iconos a las lengüetas con el método setIndicator(). Los iconos
disponibles en el sistema y cómo crear nuevos icono será estudiado en el siguiente capítulo.
4.Crea un nuevo layout con nombre tab1.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center vertical/center_horizontal"
android:text="Lengüeta 1"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout
5.Crea una nueva clase con Tab1.java:
public class Tab1 extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.tab1, container, false);
}
}
Nota sobre Java: Pulsa Ctrl-Shift-O, para que automáticamente se añadan los paquetes que
faltan. Si la clase Fragment es encontrada en más de un paquete
seleccionaandroid.support.v4.app.FragmentTabHost.
Un fragment se crea de forma muy parecida a una actividad. También dispone del
métodoonCreate(), aunque en este ejemplo no se introduce código.
Un fragment también tiene asociada una vista, aunque a diferencia de una actividad, no se
asocia en el método onCreate(), si no que dispone de un método especial para esta
tarea onCreateView().
6.Repite los dos pasos anteriores para crear tab2.xml y Tab2.java.
7.Repite de nuevo para crear el layout tab3.xml y la clase Tab3.java.
8.Modifica estos ficheros para que cada layout sea diferente y para que cada fragment visualice
el layout correspondiente.
9.Ejecuta el proyecto y verifica el resultado.
Unidad 3. Actividades e intenciones
En esta unidad seguimos trabajando con el diseño del interfaz de usuario. En lugar de tratar
aspectos de diseño visual, como hicimos en la unidad anterior, vamos a tratar temas más
relacionados con el código. En concreto nos centraremos en las Actividades y
las Intenciones. Estudiaremos también dos herramientas de gran utilidad para cualquier
aplicación: la barra de acciones y la definición de las preferencias de configuración. Además
se tratará un tipo de vista muy práctica aunque algo compleja de manejar: ListView.
Nos vamos a centrar en el ejemplo de aplicación que estamos desarrollando, Asteroides, para
añadirle diferentes actividades. A continuación se muestra el esquema de navegación entre
actividades que queremos crear:
Objetivos:
 Describir cómo el interfaz de usuario en una aplicación Android estará formado por un conjunto
de actividades.
 Mostrar como desde una actividad podemos invocar a otras y cómo podemos comunicarnos con
ellas.
 Incorporar a nuestras aplicaciones ciertos elementos prácticos como son los menús o las
preferencias.
 Describir cómo podemos utilizar y crear iconos en nuestras aplicaciones.
 Estudiar una vista muy útil en Android: ListView.
 Describir el uso de intenciones para invocar actividades estándar en Android.
Creación de nuevas actividades
El concepto de actividad en Android representa una unidad de interacción con el usuario, es lo
que coloquialmente llamamos una pantalla de la aplicación. Una aplicación suele estar
formada por una serie de actividades, de forma que el usuario puede ir navegando entre
actividades. En concreto, Android suele disponer de un botón (físico o en pantalla) que nos
permite volver a la actividad anterior, es decir la actividad que ha creado a la actividad actual.
video[Tutorial] Actividades en Android
Toda Actividad ha de tener una vista asociada, que será utilizada como interfaz de usuario.
Esta vista suele ser de tipoLayout aunque no es imprescindible, como se verá en el siguiente
ejemplo.
Una aplicación estará formada por un conjunto de actividades independientes, es decir se
trata de clases independientes que no comparten variables, aunque todas trabajan para un
objetivo común. Otro aspecto importante es que toda actividad ha de ser una subclase
de Activity.
Las aplicaciones creadas hasta ahora disponían de una única actividad. Esta era creada
automáticamente y se le asignaba la vista definida en res/layout/activity_main.xml. Esta
actividad era arrancada al comenzar la aplicación. A medida que nuestra aplicación crezca va
a ser imprescindible crear nuevas actividades. En este apartado describiremos como hacerlo.
Este proceso se puede resumir en cuatro pasos:
 — Crea un nuevo Layout para la actividad.
 — Crea una nueva clase descendiente de Activity. En esta clase tendrás que
indicar que el Layout a visualizar es el desarrollado en el punto anterior.
 — Para que nuestra aplicación sea visible será necesario activarla desde otra
actividad.
 — De forma obligatoria tendremos que registrar toda nueva actividad
en AndroidManifest.xml
Veamos un primer ejemplo de cómo crear una nueva actividad en la aplicación que estamos
desarrollando.
Ejercicio paso a paso: Implementación de una caja Acerca de
Vamos a crear una caja Acerca de… y visualizarla cuando se pulse el botón adecuado.
1. En primer lugar crea el fichero res/layout/acercade.xml. Para ello pulsa con el botón
derecho sobre una carpeta res/layout, seleccionar New > Android XML File e indica
en File acercade.xml.
2. Selecciona la lengüeta de edición en XML y copia el siguiente contenido:
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Este programa ha sido desarrollado como ejemplo en el curso de Android para
demostrar cómo se pueden lanzar nuevas actividades desde la actividad principal.">
</TextView>
3. Creamos ahora una nueva actividad, que será la responsable de visualizar esta vista.
Para ello crea el fichero AcercaDe.java.. Abre la carpeta src y pulsa con el botón derecho
sobre el nombre de paquete de la aplicación. Seleccionamos New > Class. Reemplaza
el código por:
package org.example.asteroides;
import android.app.Activity;
import android.os.Bundle;
public class AcercaDe extends Activity {
/** Called when the activity is first created. */
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acercade);
}
}
4. Pasemos ahora a crear un método en la actividad principal que será ejecutado
cuando sea pulsado el botón Acerca de.
public void lanzarAcercaDe(View view){
Intent i = new Intent(this, AcercaDe.class);
startActivity(i);
}
Nota sobre Java: Pulsa Ctrl-Shift-O, en las dos clases modificadas para que
automáticamente se añadan los paquetes que faltan.
5. Para asociar este método al botón edita el Layout activity_main.xml. Selecciona el
botón Acerca de… y en la vista de Eclipse Properties busca el atributo onClick e introduce
el valor lanzarAcercaDe.
6. Pasa a la edición xml pulsando en la lengüeta activity_main.xml y observa como en la
etiqueta <Button>correspondiente, se ha añadido el atributo:
android:onClick="lanzarAcercaDe"
NOTA: En caso de que exista algún recurso alternativo para activity_main.xmlrepite el mismo
proceso.
7. Ejecuta ahora la aplicación y pulsa en el botón Acerca de. Observarás que el resultado
no es satisfactorio ¿Qué ha ocurrido?
El problema es que toda actividad que ha de ser lanzada por una aplicación ha de ser
registrada en el fichero AndroidManifest.xml. Para registrar la actividad
abre AndroidManifest.xml y selecciona la lengüetaApplication. En Application Nodes pulsa
el botón Add… y selecciona Activity. Rellena los campos de la derecha tal y como se
muestra a continuación:
8. Guarda AndroidManifest.xml y observa como en este fichero se ha añadido:
<activity android:name=".AcercaDe"
android:label="Acerca de ..."/>
9. Ejecuta de nuevo el programa. El resultado ha de ser similar al mostrado a
continuación:
La vista mostrada en el ejemplo anterior no parece muy atractiva. Tratemos de
mejorarla aplicando un tema. Como vimos en el capítulo anterior un tema es una
colección de estilos que define el aspecto de una activad o aplicación. Puedes utilizar
alguno de los temas disponibles en Android o crear el tuyo propio.
10. En este caso utilizaremos uno de los de Android. Para ello
abre AndroidManifest.xml y selecciona la lengüeta Application. En Application Nodes pulsa
sobre .AcercaDe y a la derecha introduce en el campoTheme: el
valor: @android:style/Theme.Dialog.
11. Si lo prefieres edita directamente el fichero AndroidManifest.xml:
<activity android:name=".AcercaDe"
android:label="Acerca de ..."
android:theme="@android:style/Theme.Dialog"/>
12. Ejecuta de nuevo el programa y observa cómo mejora la apariencia:
Ejercicio paso a paso: Un escuchador de evento por código
Como acabamos de ver en un layout podemos definir el atributo
XML android:onClick nos permite indicar un método que será ejecutado al
hacer click en una vista. A este método se le conoce como escuchador de evento.
Resulta muy sencillo y además está disponible en cualquier desdendiente de la
clase View. Sin embargo esta técnica presenta dos inconvenientes. En primer lugar,
solo está disponible a partir de la versión 1.6 de Android. En segundo lugar, solo está
disponible para el evento onClick(). La clase Viewtiene otros eventos
(onLongClick(), onFocusChange(), onKey(),…) para los que no se han
definido un atributo xml. Entonces, qué hacemos si queremos trabajar con una versión
anterior a 1.6 o definir un evento distinto de onClick(). La respuesta la encontrarás
este ejercicio:
1. Abre la clase MainActivity.java y añade las líneas que aparecen subrayadas:
public class MainActivity extends Activity {
private Button bAcercaDe;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bAcercaDe =(Button) findViewById(R.id.Button03);
bAcercaDe.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
lanzarAcercaDe(null);
}
});
}
…
NOTA: En el capítulo 5 se estudiará con más detalle los escuchadores de evento.
Práctica: El botón salir
En el layout activity_main.xml hemos introducido un botón con texto “Salir”. Queremos que
cuando se pulse este botón se cierre la actividad. Para cerrar una actividad puedes llamar al
método finish(); Llamar a este método es equivalente a cuando un usuario pulsa la tecla
«retorno».
1. Realiza este trabajo utilizando un escuchador de evento por código.
2. Hazlo ahora con el atributo xml android:onClick.
3. Verifica que el resultado es el mismo en ambos casos.
NOTA: No esconveniente que en tus actividades incluyas un botón para cerrarlas. Un dispositivo
Android siempre dispone de la tecla «retorno», que tiene la misma función.
Solución:
1. Para resolverlo mediante un escuchador por código, añade en el métoco onCreate() de la
claseMainActivity el siguiente código:
Button bSalir =(Button) findViewById(R.id.button04);
bSalir.setOnClickListener(new OnClickListener() {
publicvoidonClick(View view) {
finish();
}
});
2. Para resolverlo con el atributo onClick, añade en MainActivity el método:
public void salir(View view){
finish();
}
Y añade el siguiente atributo al botón “Salir” en el layout activity_main.xml:
android:onClick="salir"
Comunicación entre actividades
Cuando una actividad ha de lanzar a otra actividad en muchos casos necesita enviarle cierta
información.
video[Tutorial] Intercambio de datos entre actividades
Android nos permite este intercambio de datos utilizando el mecanismo que es descrito a
continuación:
Cuando lances una actividad usa el siguiente código:
Intent intent = new Intent(this, MI_CLASE.class);
intent.putExtra("usuario", "Pepito Perez");
intent.putExtra("edad", 27);
startActivity(intent);
En la actividad lanzada podemos recoger los datos de la siguiente forma:
Bundle extras = getIntent().getExtras();
String s = extras.getString("usuario");
int i = extras.getInt("edad");
Cuando la actividad lanzada termina también podrá devolver datos que podrán ser recogidos por la
actividad lanzadora de la siguiente manera.
Intent intent = new Intent(this, MI_CLASE.class);
startActivityForResult(intent, 1234);
...
@Override protected void onActivityResult (int requestCode,
intresultCode, Intent data){
if (requestCode==1234 && resultCode==RESULT_OK) {
String res = data.getExtras().getString("resultado");
}
}
En la actividad llamada has de escribir:
Intent intent = new Intent();
intent.putExtra("resultado","valor");
setResult(RESULT_OK, intent);
finish();
Práctica: Comunicación entre actividades.
1. Crea un nuevo proyecto con nombre ComunicacionActividades.
2. El Layout de la actividad inicial ha de ser similar al que se muestra abajo a la izquierda.
3. Introduce el código para que cuando se pulse el botón “Verificar” se arranque una segunda actividad. A
esta actividad se le pasará como parámetro el nombre introducido en el EditText.
4. El Layout correspondiente a la segunda actividad se muestra a la derecha.
5. Al arrancar la actividad el texto del primer TextView ha de modificarse para que ponga “Hola ”+nombre
recibido+”¿Aceptas las condiciones?”
6. En esta actividad se podrán pulsar dos botones, de forma que se devuelva a la actividad principal
elString “Aceptado” o “Rechazado”, según el botón pulsado. Al pulsar cualquier botón se regresará a la
actividad anterior.
7. En la actividad principal se modificará el texto del último TextView para que ponga “Resultado: Aceptado”
o “Resultado:Rechazado”, según lo recibido.
Añadiendo un menú a una actividad
Android permite asignar menús a las actividades, que se despliegan cuando se pulsa la tecla «menú».
Este tipo de menús resultan muy interesantes en dispositivos con pantallas pequeñas dado que no ocupan
parte de la pantalla, es decir, están ocultos hasta que se pulsa la tecla de «menú».
Desde la versión 3.0 ya no es obligatorio que un dispositivo Android diponga de la tecla «menú». No
obstante, algunos dispositivos, como los de la marca Samsung, siguen incorporando esta tecla. En la
versión 3.0 aparece la barra de acciones, donde se integra el menú de las actividades. Este elemento, que
tiene una gran importancia en el diseño del interfaz de usuario en una aplicación Android, será estudiada
en el siguiente punto. En este punto estudiaremos el planteamiento anterior a la aparición de la barra de
acciones, es decir el menú de actividad.
Aunque este tipo de menús pueda parecer un elemento obseleto en una aplicación actual, va ha ser
interesante estudiarlo primero. A continuación se justifica por que:
 En la actualidad algunos usuarios utilizan terminales con una versión anterior a la 3.0. En estos
casos los menús de serán mostrados como se aparecen en este punto.
 En algunas actividades no querremos que se muestre la barra de acciones y preferimos utilizar
este tipo de menús ocultos. Por ejemplo, si queremos tener toda la pantalla para la actividad o si
la estética que buscamos no combina con la barra de acciones.
 La barra de acciones es una evolución compatible con los menús de actividad. Estos dos
elementos resultan más fáciles de entender si seguimos el orden en que han aparecido.
NOTA: En el siguiente vídeo se habla de”menús contextuales”. Este termino no es adecuado dado que
puede confundirse con otro tipo de menús. Un termino más preciso sería “menú de actividad”.
video[Tutorial] Añadiendo un menú en Android
Ejercicio paso a paso: Añadiendo un menú a una actividad
Podemos asignar un menú a nuestra actividad de forma muy sencilla.
1. Abre el proyecto de la aplicación.
2. Cuando creamos una nueva aplicación, se crea un menú inicia asociado a la
actividadMainActivity. Para modificar este menú abre el fichero res/menú/main.xml.
Aparecerá una lista con un solo de elemento de menú, action_settings (Item).
NOTA:Cuando quieras crear un nuevo menú para otra actividad, selecciona en el menú de
Eclipse File > New > Android XML File. y selecciona en el campo Resource Type: Menu.
3. El elemento de menú creado por defecto no nos interesa. Para eliminarlo selecciónalo, pulsando
sobre action_settings (Item), y haz clic en el botón Remove.
4. Añade un elemento de tipo Item. Introduce en el campo Id el valor @+id/config, en el campo Title el
valor Configuración. y en el campo Icon @android:drawable/ic_menu_preferences.
5. Repite el proceso para introducir un nuevo ítem con Id tomando el valor @+id/acercaDe, Title con
el valor Acerca de … e Icon con el valor @android:drawable/ic_menu_info_details.
6. Pulsa la lengüeta .xml. El fichero xml resultante se muestra a continuación:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="Configuración"
android:id="@+id/config"
android:icon="@android:drawable/ic_menu_preferences"/>
<item android:title="Acerca de..."
android:id="@+id/acercaDe"
android:icon="@android:drawable/ic_menu_info_details"/>
</menu>
La apariencia de este menú se muestra a continuación. Esta apariencia puede cambiar
dependiendo de la versión de Android.
7. Para activar el menú has de introducir el siguiente código al final de MainActivity.java:
@Override public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true; /** true -> el menú yaestá visible */
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.acercaDe:
lanzarAcercaDe(null);
break;
}
return true; /** true -> consumimos el item, no se propaga*/
}
8. Ejecuta el programa y pulsa la tecla «menú» del terminal. En la parte inferior de la pantalla
ha de aparecer los dos ítems de menu como se muestra en la figura anterior.
La barra de acciones (ActionBar)
video[Tutorial] Añadiendo un menú en Android
Desde la versión 3.0, se introdujo en Android un nuevo elemento en la interfaz de usuario: la barra de
acciones o ActionBar. Situada en la parte superior de la pantalla, fue creada para que el usuario tuviera
una experiencia unificada a través de las distintas aplicaciones. La barra de acciones aglutina varios
elementos; los más habituales son el icono de la aplicación con su nombre y los botones de acciones
frecuentes. Las acciones menos utilizadas se sitúan en un menú desplegable, que se abrirá desde el
botón «Overflow». Si la aplicación dispone de pestañas (tabs), estas podrán situarse en la barra de tareas.
También pueden añadirse otros elementos como listas desplegables y otros tipos de widgets incrustados,
como el widget de búsqueda que veremos más adelante.
En caso de disponer de menos tamaño de pantalla el sistema puede redistribuir los elementos y pasar
alguna acción al menú de «Overflow». Por ejemplo, en un móvil el ActionBar anterior se podría ver de
la siguiente manera:
Los dispositivos anteriores a la 3.0 requerían una tecla física para mostrar el menú de la actividad. Sin
embargo, con esta versión dicha tecla deja de ser un requisito de los terminales y los menús pasan a
mostrarse en la barra de acciones. En los dispositivos que sí que dispongan de este botón físico, es
posible que los tres puntos que representan el menú de «Overflow» no se representen en la barra de
acciones. En este caso tienes que pulsar el botón físico para desplegar este menú.
La barra de acciones se configura igual que los menús disponibles desde la primera versión. Es decir, a
través de ficheros XML de menús, almacenados en res/menu. Esto permite diseñar el menú de una
aplicación de la forma convencional. Cuando la aplicación se ejecute en una versión inferior a la 3.0, el
menú se mostrará de forma tradicional. Cuando el usuario pulse la tecla «menú» aparecerá:
Pero, en caso de disponer de una versión 3.0 o superior, se mostrará en la barra de acciones.
Añadir un ActionBar a la aplicación es muy sencillo. Es más, gracias a que se utiliza la misma
herramienta que para mostrar menús en dispositivos con versiones anteriores, todas las opciones
delActionBar estarán disponibles independientemente de la versión que se esté utilizando. Por lo tanto,
no hay que realizar ningún paso para que se visualice la barra de acciones. Todos los temas de Android a
partir de la versión 3.0 incorporan por defecto la barra de acciones visible (menos los que acaban
enNoActionBar). Si se desea ocultar la barra de acciones desde código es muy sencillo; pero mostrarla
una vez aplicado un estilo que la deshabilite es imposible.
Desde finales de 2013 también podemos utilizar ActionBar en versiones anteriores a la 3,0 gracias a la
aparición de una librería de compatibilidad. Veremos como realizarlo en uno de los siguientes ejercicios.
Ejercicio paso a paso: Añadiendo un ActionBar a nuestra aplicación.
1. Reemplaza el contenido del fichero res/menu/main.xml por:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="Configuración"
android:id="@+id/config"
android:icon="@android:drawable/ic_menu_preferences"
android:orderInCategory="95"
android:showAsAction="ifRoom"/>
<item android:title="Acerca de..."
android:id="@+id/acercaDe"
android:icon="@android:drawable/ic_menu_info_details"
android:showAsAction="ifRoom|withText"/>
<item android:title="Buscar"
android:id="@+id/menu_buscar"
android:orderInCategory="90"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="always|collapseActionView"/>
</menu>
Este fichero XML es el que define los iconos y acciones a mostrar. Como ya hemos dicho, para los
dispositivos con una versión 3.0 o superior, este menú se muestra en la barra de acciones. Las
acciones que indiquen en el atributo showAsAction la palabra always serán mostrados siempre,
sin importar si caben o no. El uso de estas acciones debería limitarse a unas pocas, o incluso mejor si
no hay ninguna, ya que al forzar que se visualicen todas al mismo tiempo podrían verse
incorrectamente. Las acciones que indiquen ifRoom serán mostradas en la barra de acciones si hay
espacio disponible, y serán movidas al menú de Overflow si no lo hay. En esta categoría se deberían
encontrar la mayoría de acciones. Si se indica never la acción nunca se mostrará en la barra de
acciones, sin importar el espacio disponible. En este grupo se deberían situar acciones como
modificar las preferencias, que deben estar disponibles al usuario; pero no visibles en todo
momento.
Las acciones son ordenadas de izquierda a derecha según lo indicado en orderInCategory, con
las acciones con un número más pequeño más a la izquierda. Si todas las acciones no caben en la
barra, las que tienen un número menor son movidas al menú de Overflow.
2. Ejecuta la aplicación; podrás ver como aparece la barra de acciones en la parte de arriba, con los
botones que hemos definido.
Creación y uso de iconos
En el apartado anterior hemos creado un menú que hacía uso de dos iconos. Se utilizaban iconos
disponibles en el sistema Android, es decir, se han utilizado recursos del sistema Android. Otra
alternativa es crear tus propios iconos y almacenarlos en la carpeta res/drawable.
video[Tutorial] Añadiendo iconos en Android
tipo de iconos finalidad Ejemplos
lanzadores
representa la aplicación en la pantalla principal del
dispositivo
Menú
se muestran cuando presione el botón Menú. Cada
actividad puede definir su propio menú.
barra de acciones
a partir de la versión 3.0 con el aumento de pantalla de la
tabletas las actividades pueden disponer de una barra de
iconos siempre visible.
barra de estado
barra con pequeños iconos que nos alertan de
notificaciones (ver CAPÍTULO 8)
Pestañas
Las pestañas (Tabs) nos permiten seleccionar entre varias
vistas.
Otros
También es muy frecuente el uso de iconos en cuadros de
dialogo y en ListView.
Tabla 2: Tipos de iconos en Android.
Si estás interesado en utilizar iconos disponibles en el sistema, encontrarás el inconveniente
de no poder seleccionar el que te interese de forma sencilla. Recuerda como en el punto 6 del
último ejercicio, cuando introducías el campo Icon en la definición de un ítem de menú, no
disponía del botón Browse… para poder seleccionar el icono desde una lista. Para conocer los
iconos disponibles te recomendamos que utilices el primer enlace de la lista mostrada a
continuación.
Si por el contrario decides diseñar tus propios iconos has de tener en cuenta algunos
aspectos. En primer lugar, recuerda que Android ha sido concebido para ser utilizado en
dispositivos con gran varidad de densidades gráficas. Este rango puede ir desde 100
pixeles/pulgada (ldpi) hasta 340 pixeles/pulgada (xhdpi). Por lo tanto, resulta interesante que
plantees tus diseños con una resolución como mínimo de 300 pixeles/pulgada. Cuando se
represente en un dispositivo el sistema reajustará el tamaño del icono para que se ajuste al
espacio disponible y, por supuesto, siempre es conveniente realizar una reducción en lugar de
tener que ampliar. Ahora bién, en muchos casos este reajuste automático de tamaño puede
no ser se satisfactorio (en el siguiente ejercicio se muestra un ejemplo). En estos casos,
podremos hacer usos de los recursos alternativos y crear diferentes iconos para diferentes
densidades gráficas. Para ayudarte en esta tarea puedes utilizar la herramienta Android Asset
Studio que se incluye en la siguiente lista de enlaces.
En segundo lugar, tu aplicación va a ser ejecutada dentro de un sistema donde se utilizan
ciertas guias de estilo. Si quieres que tus iconos no desentonen lee la documentación que se
indica a continuación.
Enlaces de interés:
Lista de recursos drawable: En la documentación oficial de Android no aparece un listado con los
recursos disponibles. Para ver gráficamente todos los recursos drawable del sistema puedes acceder a
la siguiente página:
http://androiddrawableexplorer.appspot.com/
Android Asset Studio:Puedes crear tus propios iconos de forma sencilla utilizando la siguiente
herramienta online:
http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html
Guía de estilo para iconos: La siguiente página describe las guías de estilo para los iconos en
las distintas versiones de Android:
http://developer.android.com/guide/practices/ui_guidelines/icon_design.html
Ejercicio paso a paso: Creación de iconos personalizados
Si te gusta el diseño o lo consideras interesante para tu formación, pueden resultar de gran
utilidad las herramientas descritas anteriormente. Vemos un ejemplo práctico: El diseñador
gráfico de nuestra empresa, nos acaba de pasar el icono asociado para iniciar a la aplicación
que estamos diseñando (launcher Icon).
Pulsa para descargar el grafico
grafico_aplicacion.PNG
El problema es que no estamos seguros de que se va a ver correctamente para las diferentes
densidades gráficas que podemos encontrar en los dispositivos Android. Para asegurarnos
que esto sea así realizaríamos los siguientes pasos:
1. Descarga el gráfico anterior de www.androidcurso.com y llámale icon.png.
2. Accede a Android Asset Studio:
http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html
3. Selecciona la opción: Launcher icons
4. Pulsa sobre el botón Image y selecciona el fichero anterior.
5. En la parte inferior de la página podrás previsualizar como quedarán las imágenes
para las cuatro densidades gráficas de Android.
6. El resultado solo es aceptable para la opción xhdpi. En el resto de los casos ha
desaparecido alguna línea o el texto no se lee. Va a ser imprescindible retocar estos
iconos.
7. Descarga el fichero pulsando en
8. Retoca el icono hdpi para que se vean todas las líneas azules.
9. Retoca el icono mdpi y ldpi para que se pueda leer el texto “Aplicación”.
10. Asigna los iconos retocados a las carpetas adecuadas (res/drawable) de una
aplicación (por ejemplo la creada en la sección “Comunicación entre actividades”).
11. Visualiza el resultado instalando la aplicación en diferentes dispositivos con
diferentes densidades gráficas.
Práctica: Creación de iconos para la aplicación
1. Dibuja o busca en Internet un gráfico que sea adecuado para usar como icono de inicio en la
aplicación.
2. Repite los pasos indicados en el ejercicio anterior para crear los iconos en las diferentes
densidades gráficas.
Añadiendo preferencias de usuario
Android nos facilita la configuración de nuestro programa, al permitir añadir una lista de
preferencias que el usuario podrá modificar. Las preferencias también pueden ser utilizadas
para que tu aplicación almacene de forma permanente información. En la unidad 9 se
estudiará cómo realizar esta función.
video[Tutorial] Añadir preferencias en Android
Ejercicio paso a paso: Añadiendo preferencias a Asteroides
1. Abre el proyecto Asteroides.
2. Pulsa con el botón derecho sobre la carpeta res y selecciona la opción New > Other… Selecciona Android
> Android XML File.
3. Completa los siguientes campos Resource Type: Preference, File: preferencias.xml. Se creará el
fichero res/xml/preferencias.xml.
4. Selecciona la lengüeta preferencias.xml para editar el fichero en xml.
5. Introduce el siguiente código:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="preferencias_principal" >
<CheckBoxPreference
android:key="musica"
android:title="Reproducir música"
android:summary="Se reproduce música de fondo"/>
<ListPreference
android:key="graficos"
android:title="Tipo de gráficos"
android:summary="Se escoge la representación de gráficos"
android:entries="@array/tiposGraficos"
android:entryValues="@array/tiposGraficosValores"
android:defaultValue="1"/>
<EditTextPreference
android:key="fragmentos"
android:title="Número de Fragmentos"
android:summary="En cuantos trozos se divide un asteroide"
android:defaultValue="3"/>
</PreferenceScreen>
El resultado que obtendremos se muestra a continuación:
6. Para almacenar los valores del desplegable has de crear el fichero /res/values/arrays.xml con el
siguiente contenido:
<resources>
<string-array name="tiposGraficos">
<item>vectorial</item>
<item>bitmap</item>
<item>3D</item>
</string-array>
<string-array name="tiposGraficosValores">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
</resources>
7. En lugar de trabajar directamente con xml. También puedes introducir las distintas preferencias utilizando la
lengüetaStructure. Investiga esta opción.
8. Crea ahora una nueva clase Preferencias.java con el siguiente código:
package org.example.asteroides;
public class Preferencias extends PreferenceActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferencias);
}
}
Nota sobre Java:Pulsa Ctrl-Shift-O, para que automáticamente se añadan los
paquetes que faltan.
NOTA: Desde el nivel de API 11 el método addPreferencesFromResource()ha sido marcado como
obsoleto. En lugar de usar la clase FragmentActivityse recomienda utilizar PreferenceFragments. El
uso de fragments será estudiado más adelante.
9. No hay que olvidar registrar toda nueva actividad en AndroidManifest.xml.
10. Añade a Asteroides.java el método lanzarPreferencias(). Este método ha de tener el mismo código
quelanzarAcercaDe() pero lanzando la actividad Preferencias.
11. En el Layout activity_main.xml añade al botón con texto “Configurar” en el atributo onClick el
valorlanzarPreferencias.
12. Para activar la configuración desde la opción de menú añade el siguiente código en el
ficheroAsteroides.java en el método onOptionsItemSelected() dentro del switch.
case R.id.config:
lanzarPreferencias(null);
break;
13. Arranca la aplicación y verifica que puedes lanzar las preferencias mediante las dos alternativas.
Organizando preferencias
Cuando el número de preferencias es grande resulta interesante organizarlas de forma
adecuada. Una posibilidad consiste en dividirlas en varias pantallas. De forma que cuando se
seleccione una opción en la primera pantalla, se abra una nueva pantalla de preferencias.
Para organizar las preferencias de esta forma usa el siguiente esquema:
<PreferenceScreen>
<CheckBoxPreference …/>
<EditTextPreference …/>
…
<PreferenceScreen android:title=”Modo multijugador”>
<CheckBoxPreference …/>
<EditTextPreference …/>
…
</PreferenceScreen>
</PreferenceScreen>
Práctica: Organizando preferencias(I)
1. Crea una nueva lista de preferencias <PreferenceScreen> dentro de la lista de
preferencias del fichero res/xml/preferencias.xml.
2. Asígnale al parámetro android:title el valor “Modo multijugador”.
3. Crea tres elementos dentro de esta lista: Activar multijugador, Máximo de
jugadores y Tipo de conexión. Para este ultimo han de poder escogerse los
valores: Bluetooth, Wi-Fi e Internet.
Otra alternativa para organizar las preferencias consiste en agruparlas por categorías. Con
esta opción se visualizarán en la misma pantalla, pero separadas por grupos. Has de seguir el
siguiente esquema:
<PreferenceScreen>
<CheckBoxPreference …/>
<EditTextPreference …/>
…
<PreferenceCategory android:title=”Modo multijugador”>
<CheckBoxPreference …/>
<EditTextPreference …/>
.. …
</PreferenceCategory>
</PreferenceScreen>
A continuación se representa la forma en la que Android muestra las categorías:
Práctica: Organizando preferencias(II)
1. Modifica la práctica anterior para que en lugar de mostrar las propiedades en dos
pantallas, las muestre en una sola, tal y como se muestra en la imagen anterior.
Como se almacenan las preferencias de usuario
Si un usuario modifica el valor de una preferencia, este quedará almacenado de forma
permanente en el dispositivo. Para conseguir esta persistencia Android almacena las
preferencias seleccionadas en un fichero XML dentro de la
carpeta data/data/nombre.del.paquete/files/shared_prefs. Donde nombre.del.paquete ha de
ser reemplazado por el paquete de la aplicación. El nombre del fichero para almacenar las
preferencias de usuario ha de ser siempre nombre.del.paquete_preferences.xml.Esto
significa que solo puede haber unas preferencias de usuario por aplicación. Como se
estudiará en el capítulo 9 pueden haber otros ficheros de preferencia, pero a diferencia de las
preferencias de usuario no pueden ser editadas directamente por el usuario sino que hay que
acceder a ellas por código.
Ejercicio paso a paso: Donde se almacenan las preferencias de usuario
Veamos donde se han almacenado las preferencias que acabamos de crear:
1. Para navegar por el sistema de ficheros de un dispositivo (tanto virtual como real)
accede al menú Window > Show View > Others… > Android > File Explorer.
2. Busca el siguiente fichero: /data/data/org.examples.asteroides/shared_prefs/
org.examples.asteroide_preferences.xml
3. Pulsa el botón del disquete para descargar el fichero en tu PC.
4. Visualiza su contenido. Tiene que ser similar a:
<map>
<boolean name="musica"value="true" />
<string name="graficos">1</string>
<string name="fragmentos">3</string>
</map>
Accediendo a los valores de las preferencias
Por supuesto, será necesario acceder a los valores de las preferencias para alterar el funcionamiento de
nuestra aplicación. El siguiente ejemplo nos muestra cómo realizarlo:
public void mostrarPreferencias(){
SharedPreferences pref =
PreferenceManager.getDefaultSharedPreferences(this);
String s = "música: "+ pref.getBoolean("musica",true)
+", gráficos: " +
pref.getString("graficos","?");
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
La función comienza creando el objeto pref de la clase SharedPreferences y le asigna las
preferencias definidas para la aplicación. A continuación crea el String s y le asigna los valores de
dos de las preferencias. Se utilizan los métodos pref.getBoolean() y pref.getString(),
que disponen de dos parámetros: el valor dekeyque queremos buscar ("musica" y "graficos") y el valor
asignado por defecto en caso de no encontrar esta key.
Finalmente se visualiza el resultado utilizando la clase Toast. Los tres parámetros indicados son el
contexto (nuestra actividad), el String a mostrar y el tiempo que se estará mostrando esta
información.
Ejercicio paso a paso: Accediendo a los valores de las preferencias
1. Copia la función anterior en la clase Asteroides. Añade el parámetro que se muestra a
continuación mostrarPreferencias(View view).
2. Asígnala al atributo onClick del botón Jugar el método anterior.
3. Visualiza también el resto de las preferencias que hayas introducido.
Creando actividades en Mis Lugares
Creando la actividad VistaLugar de Mis Lugares
En este apartado crearemos la actividad VistaLugar en la aplicación Mis Lugares. Esta actividad nos
mostrará la información que hemos almacenado de un determinado lugar y nos permitirá realizar gran
cantidad de acciones sobre este lugar (mostrar en mapa, llamar por teléfono, compartir en redes sociales,
etc.). Desde esta actividad podremos cambiar algunos valores de modificación frecuente. En concreto: la
valoración, fecha de visita y fotografía.
Ejercicio paso a paso: Creación de Ia actividad VistaLugar.
1. Abre el proyecto MisLugares.
2. Copia dentro de la carpeta res/drawable los gráficos que encontrarás en el siguiente
fichero:http://www.dcomg.upv.es/~jtomas/android/ficheros/mislugares.zip
Crea un nuevo layout con nombre vista_lugar.xml. Copia el siguiente código para usarlo como base:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/nombre"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center"
android:text="Nombres del lugar"
android:textAppearance="?android:attr/textAppearanceLarge" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/logo_tipo"
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="logo del tipo"
android:src="@drawable/otros" />
<TextView
android:id="@+id/tipo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="tipo del lugar" />
</LinearLayout>
…
<RatingBar
android:id="@+id/valoracion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_toRightOf="@+id/foto"
android:rating="3" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/foto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="fotografía"
android:src="@drawable/foto_epsg" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right" >
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="logo camara"
android:src="@android:drawable/ic_menu_camera" />
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="logo galeria"
android:src="@android:drawable/ic_menu_gallery" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
</ScrollView>
Observa como el elemento exterior es un ScrollView esto es conveniente cuando pensemos que los
elementos de layout no cabrán en la pantalla. En este caso el usuario podrá desplazar verticalmente el
layout arrastrando con el dedo. Dado que algunas pantallas pueden ser muy pequeñas la mayoría de
diseños han de incorporar un ScrollView.
Dentro de este elemento tenemos un LinearLayout para organizar las vistas verticalmente. La
primera vista es un TextView cuyo id es nombre. Se ha asignado un valor para text inicial, que
será reemplazado por el nombre del lugar. La única función que tiene este texto inicial es ayudarnos en
el diseño. El siguiente elemento es un LinearLayout vertical que contiene un ImageView y
un TextView. Este elemento será utilizado para indicar el tipo de lugar.
Los puntos suspensivos indican el lugar donde tendrás que insertar el resto de elementos que no se han
incluido (dirección, teléfono, etc.). El siguiente elemento que se incluye es un RatingBar donde
podremos introducir una valoración del lugar. El último elemento es un FrameLayout que permite
superponer varias vistas. Serán dibujadas en el orden en que las indicamos. En el fondo se dibuja
unImageView con una fotografía de la EPSG. El atributo adjustViewBounds indica que la imagen
sea escalada para ocupar todo el espacio disponible. Sobre la fotografía se dibujará
un LinearLayoutcon dos ImageView. Estos botones permitirán cambiar la fotografía desde la
cámara o desde la galería.
4. Reemplaza los puntos suspensivos por los elementos que faltan para obtener la apariencia mostrada
al principio de este punto. Utiliza los recursos del sistema mostrados en la siguiente tabla. Identifica
dada TextView con el id que se indica.
Recurso para ImageView Id para TextView
@android:drawable/ic_menu_myplaces @+id/direccion
@android:drawable/ic_menu_call @+id/telefono
@android:drawable/ic_menu_mapmode @+id/url
@android:drawable/ic_menu_info_details @+id/comentario
@android:drawable/ic_menu_my_calendar @+id/fecha
@android:drawable/ic_menu_recent_history @+id/hora
5. Crea la clase VistaLugar y reemplaza el código por el siguiente:
public class VistaLugar extends Activity {
private long id;
private Lugar lugar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.vista_lugar);
Bundle extras = getIntent().getExtras();
id = extras.getLong("id", -1);
lugar = Lugares.elemento((int) id);
TextView nombre = (TextView) findViewById(R.id.nombre);
nombre.setText(lugar.getNombre());
ImageView logo_tipo = (ImageView)
findViewById(R.id.logo_tipo);
logo_tipo.setImageResource(lugar.getTipo().getRecurso());
TextView tipo = (TextView) findViewById(R.id.tipo);
tipo.setText(lugar.getTipo().getTexto());
TextView direccion = (TextView)
findViewById(R.id.direccion);
direccion.setText(lugar.getDireccion());
TextView telefono = (TextView) findViewById(R.id.telefono);
telefono.setText(Integer.toString(lugar.getTelefono()));
TextView url = (TextView) findViewById(R.id.url);
url.setText(lugar.getUrl());
TextView comentario = (TextView)
findViewById(R.id.comentario);
comentario.setText(lugar.getComentario());
TextView fecha = (TextView) findViewById(R.id.fecha);
fecha.setText(DateFormat.getDateInstance().format(
new Date(lugar.getFecha())));
TextView hora = (TextView) findViewById(R.id.hora);
hora.setText(DateFormat.getTimeInstance().format(
new Date(lugar.getFecha())));
RatingBar valoracion = (RatingBar)
findViewById(R.id.valoracion);
valoracion.setRating(lugar.getValoracion());
valoracion.setOnRatingBarChangeListener(
newOnRatingBarChangeListener() {
@Override public void onRatingChanged(RatingBar
ratingBar,
float valor, boolean fromUser) {
lugar.setValoracion(valor);
}
});
}
}
Nota sobre Java: Pulsa Ctrl-Shift-O, para que automáticamente se añadan los imports con los paquetes que faltan. Dos
clases aparecen en varios paquetes, selecciona java.text.DateFormat y java.util.Date.
El método onCreate() será ejecutado cuando se cree la actividad y en el tenemos que asociar un
layout (setContentView(R.layout.vista_lugar)) e inicializar todos sus valores. Lo
primero que se hace es averiguar el id del lugar a mostrar, que ha sido pasado en un extra. A partir de
este id obtenemos el objeto Lugar a mostrar. Tanto este objeto como el id son almacenados en
variables globales para que puedan ser accedidas desde cualquier método de la actividad.
Observa cómo se obtiene un objeto de cada uno de los elementos de la vista utilizando el
métodofindViewById(). A continuación este objeto es modificado según el valor del lugar que
estamos representando. Al final se realiza una acción especial con el objeto valoracion. Utilizando el
métodosetOnRatingBarChangeListener() para asignarle un escuchador de eventos
al RatingBar que es creado allí mismo. Este evento será activado cuando el usuario modifique la
valoración asignada. El código a ejecutar consiste en llamar a al método setValoracion() del
objeto lugar con la nueva valoración.
6. En la primera unidad se creó el proyecto MisLugaresJava. Abre este proyecto y selecciona las
clases GeoPunto, Lugar, Lugares y TipoLugar (Puedes seleccionar varios ficheros
manteniendo la tecla Ctrl pulsada). Con el botón derecho selecciona la opción Copy. Con el botón
derecho pulsa sobre MisLugares/srv/com.example.mislugares y selecciona la opción Paste.
7. Abre la clase TipoLugar y asigna un recurso drawable a cada tipo de lugar. Puedes utilizar la
opción de autocompletar, es decir, escribe R.drawable. y espera a que el sistema te dé una alternativa.
public enum TipoLugar {
OTROS ("Otros", R.drawable.otros),
RESTAURANTE ("Restaurante", R.drawable.restaurante),
BAR("Bar", R.drawable.bar),
…
8. Añade en la clase ActivityMain el siguiente método:
public void lanzarVistaLugar(View view){
Intent i = new Intent(this, VistaLugar.class);
i.putExtra("id", (long)0);
startActivity(i);
}
Este método lanzará la actividad VistaLugar pasándole como id del lugar a visualizar siempre 0. Más
adelante mostraremos algunas alternativas para que el usuario pueda seleccionar el lugar a mostrar.
9. En el layout/activity_main.xml añade el atributo onClick en el primer botón.
<Button
…
android:onClick="lanzarVistaLugar"
android:text="@string/accion_mostrar" />
10. Repite este proceso en layout-land/activity_main.xml.
11. Ejecuta la aplicación. Aparecerá un error cuando pulses en el botón Mostrar Lugares. Siempre un
error en ejecución es el momento de visualizar el LogCat. No es sencillo analizar la información que se
muestra, pero es muy importante que te acostumbres a buscar la causa del problema en el LogCat. En
este caso la información clave se muestra a continuación:
12. Para resolver el error en ejecución registra la nueva actividad en AndroidManifest.xml.
13. Verifica que la aplicación muestra siempre el primer lugar.
Ejercicio paso a paso: Un cuadro de dialogo para indicar el id de lugar
Tras realizar el ejercicio anterior comprobarás que siempre se visualiza el lugar con id =
0 (i.putExtra("id", (long)0)). En este ejercicio vamos a introducir un cuadro de dialogo
que permita introducir al usuario el id que desea visualizar.
Ha de quedar claro que esta es una forma más correcta de diseñar el interfaz de usuario. En la siguiente
unidad reemplazaremos este cuadro de dialogo por un ListView.
1. Abre la clase MainActivity del proyecto MisLugares.
2. Reemplaza el método por el lanzar VistaLugar() siguiente:
public void lanzarVistaLugar(View view){
final EditText entrada = new EditText(this);
entrada.setText("0");
new AlertDialog.Builder(this)
.setTitle("Selección de lugar")
.setMessage("indica su id:")
.setView(entrada)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
long id = Long.parseLong(entrada.getText().toString());
Intent i = new Intent(MainActivity.this, VistaLugar.class);
i.putExtra("id", id);
startActivity(i);
}})
.setNegativeButton("Cancelar", null)
.show();
}
Nota sobre Java: En Java es posible crea un objeto sin que este disponga de un identificador de
objeto. Este tipo de objeto se conoce como objeto anónimo. El código mostrado a continuación a la
derecha es equivalente al de la izquierda.
Clase objeto = new Clase(); newClase().metodo();
objeto.metodo();
Un objeto anónimo no tiene identificador por lo que solo puede ser usado donde es creado. En
el método anterior se ha creado un objeto anónimo de la
clase AlertDialog.Builder. Observa cómo no se llama a un método, sino a una cadena
de métodos. Esto es posible porque los métodos de la claseAlertDialog.Builder retornan
el objeto que estamos creando. Por lo tanto, cada método es aplicado al objeto devuelto por el método
anterior.
En Android puedes usar la clase AlertDialog para crear un cuadro de dialogo configurable. Si te
fijas en la captura anterior están formados por cuatro elementos, de arriba abajo: título, mensaje, vista y
botones. Estos elementos pueden ser configurados mediante los método setTitle(),
setMessage(), setView(), setPositiveButton() y setNegativeButton().
La vista que se utiliza en este diálogo es un EditText, inicializado con un texto. En caso de necesitar
varias entradas se puede crear una vista de tipo layout, que contendría estas entradas. Se han introducido
dos botones, indicando el texto del botón y un escuchador de evento que será llamado cuando se pulse el
botón. Finalmente se llama al método show() para que se visualice el cuadro de diálogo.
3. Verifica que funciona correctamente. Pero cuidado, no se verifica que el id sea válido, por lo que
ocurrirá un error si es incorrecto.
Práctica: Ocultar elementos en VistaLugar
En ocasiones no se dispondrá de parte la información de un lugar. En estos casos, puede resultar más
conveniente desde un punto de vista estético, no mostrar cambios sin información en la
actividadVistaLugar. Por ejemplo, si el campo de teléfono es igual a 0, podríamos usar el siguiente
código para que no se muestre:
if (lugar.getTelefono() == 0) {
findViewById(R.id.p_telefono).setVisibility(View.GONE);
} else {
TextView telefono = (TextView) findViewById(R.id.telefono);
telefono.setText(Integer.toString(lugar.getTelefono()));
}
Para ocultarlo, en el layout p_telefono, ponemos el valor propiedad visivility al valor GONE. Este
atributo es aplicado a cualquier tipo de vista. Otros posibles valores para este atributo
son VISIBLE eINVISIBLE. Tanto con GONE como con INVISIBLE la vista no se verá. Pero
con INVISIBLE el espacio ocupado por la vista se mantiene, mientras que con GONE este espacio es
eliminado.
Trata de realizar un proceso similar a este para los campos dirección, telefono,
url y comentario.
Ejercicio paso a paso: Añadir una barra de acciones a VistaLugar
En este ejercicio vamos a añadir a la actividad un menú a la barra de acciones similar al que se muestra a
continuación:
1. En primer lugar crea el fichero res/menu/vista_lugar.xml que contendrá las acciones a mostrar. Para
ello pulsa con el botón derecho sobre una carpeta del proyecto MisLugares, seleccionar New > Android
XML File e indica en Resource Type: Menu y en File: vista_lugar.
2. Selecciona la lengüeta de edición en XML y copia el siguiente código:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/accion_compartir"
android:title="compartir"
android:icon="@android:drawable/ic_menu_share"
android:orderInCategory="10"
android:showAsAction="ifRoom"/>
<item
android:id="@+id/accion_llegar"
android:title="cómo llegar"
android:icon="@android:drawable/ic_menu_directions"
android:orderInCategory="20"
android:showAsAction="ifRoom"/>
<item
android:id="@+id/accion_editar"
android:title="editar"
android:icon="@android:drawable/ic_menu_edit"
android:orderInCategory="30"
android:showAsAction="ifRoom"/>
<item
android:id="@+id/accion_borrar"
android:title="borrar"
android:icon="@android:drawable/ic_menu_delete"
android:orderInCategory="40"
android:showAsAction="ifRoom"/>
</menu>
3. En la clase VistaLugar añade los siguientes métodos:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.vista_lugar,
menu); returntrue;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.accion_compartir:
return true;
case R.id.accion_llegar:
return true;
case R.id.accion_editar:
return true;
case R.id.accion_borrar:
Lugares.borrar((int) id);
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
4. Ejecuta la aplicación y borra un lugar. Verifica como si tratas de visualizar el mismo id ahora se
muestra el siguiente lugar.
Práctica: Un cuadro de dialogo para confirmar el borrado
Un usuario podría pulsar por error el botón de borra, por lo que sería muy conveniente pedir una
confirmación antes de borrar.
1. Crea un nuevo método en la actividad.
2. Modifica el código asociado a case R.id.accion_borrar: para que se llame a este método.
3. En el método crea un cuadro de dialogo siguiendo el esquema planteado en el ejercicio anterior.
Puede ser similar al siguiente.
Creando la actividad EdicionLugar de Mis Lugares
En este apartado crearemos otra actividad en la aplicación Mis Lugares, EdicionLugar. Esta
actividad nos permitirá modificar la mayoría de valores asignados a un lugar (se excluyen los valores
que se modifican desde VistaLugar: Valoración, fecha y foto):
Práctica: Creación de la actividad EdicionLugar
1. Abre el proyecto MisLugares y verifica que existe el layout edición_lugar.xml. En caso contrario
realiza la práctica Un formulario para introducir nuevos lugares
(http://www.androidcurso.com/index.php/115).
2. Crea la clase EdicionLugar. Y copia en esta clase los atributos y el método onCreate() de la
clase VistaLugar.
3. Añade las siguientes atributos a la clase:
private EditText nombre;
private Spinner tipo;
private EditText direccion;
private EditText telefono;
private EditText url;
private EditText comentario;
De esta forma estos seis objetos serán accesibles desde cualquier método de la clase, en lugar de estar
declarados solo en el método onCreate().
4. Reemplaza la vista a mostrar en setContentView() por la adecuada.
5. El paso de parámetros puede realizarse de la misma forma.
6. La creación e inicialización de los objetos nombre, direccion, telefono,
url y comentariopuede realizarse de forma similar al copiado. Pero ahora, no han de ser declarados
en el método, al estar declarados como atributos. Por lo tanto, has de eliminar el TextView inicial de
cada objeto. Además, estos objetos ahora son de la clase EditText en lugar de TextView. Por lo
tanto, reemplaza(TextView) por (EditText).
7. Puedes eliminar el resto del código de este método.
8. En la clase VistaLugar dentro del método onOptionsItemSelected(), añade el código
necesario para que se abra la actividad que acabas de crear.
9. Ejecuta el proyecto. Pero antes, piensa si falta alguna acción por realizar.
Ejercicio paso a paso: Inicializar el Spinner en EdicionLugar
Como has podido verificar en la ejecución anterior el Spinner (lista desplegable) no muestra ningún
valor. En este ejercicio trataremos que funcione adecuadamente:
1. Añade el siguiente código el método onCreate():
Spinner tipo = (Spinner) findViewById(R.id.tipo);
ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, TipoLugar.getNombres());
adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
tipo.setAdapter(adaptador);
tipo.setSelection(lugar.getTipo().ordinal());
Para inicializar los valores que puede tomar un Spinner necesitamos una clase especial conocida
como Adapter. Esta clase será estudiada en la siguiente unidad. De momento solo adelantar que un
Adapter va a crear una lista de vistas, inicializándolas con unos valores determinados. La
claseArrayAdapter<String> es un tipo de Adapter que permite inicializar sus valores a partir de
un array deString. Su constructor necesita tres parámetros: un contexto (usamos la actividad actual),
una vista para mostrar elemento (usamos un vista definida en el sistema) y un array de String. Para el
último parámetro necesitamos un array con todos los valores que puede tomar el
enumerado TipoLugar.Para obtener este array se define un nuevo método que se mostrará a
continuación.
El siguiente método, setDropDownViewResource(), permite indicar una vista alternativa que será
usada cuando se despliegue el Spinner. En la versión 4.x esta vista es un poco más grande que la
usada en el método anterior para poder seleccionarla cómodamente con el dedo. En la versión 2.x
muestra círculos seleccionables a la derecha de cada elemento. Este código concluye asignando el
adaptador al Spinner y poniendo un valor inicial según el tipo actual de lugar.
2. Añade el siguiente método a la clase TipoLugar:
public static String[] getNombres() {
String[] resultado = new
String[TipoLugar.values().length];
for(TipoLugar tipo : TipoLugar.values()) {
resultado[tipo.ordinal()] = tipo.texto;
}
return resultado;
}
3. Ejecuta la aplicación y verifica que la lista desplegable funciona correctamente..
Práctica: Añadir una barra de acciones a EdicionLugar
En esta práctica vamos a añadir a la actividad un menú en la barra de acciones similar al que se muestra
a continuación:
1. Crea un nuevo recurso de menú con las opciones que se indican.
2. Asocia este menú a la actividad EdicionLugar con el método onCreateOptionsMenu().
3. Crea el método onOptionsItemSelected() de manera que cuando se seleccione la
acciónGuardar se ejecute el siguiente código:
lugar.setNombre(nombre.getText().toString());
lugar.setTipo(TipoLugar.values()[tipo.getSelectedItemPosition()]);
lugar.setDireccion(direccion.getText().toString());
lugar.setTelefono(Integer.parseInt(telefono.getText().toString()));
lugar.setUrl(url.getText().toString());
lugar.setComentario(comentario.getText().toString());
finish();
Ejecuta la aplicación. Modifica algún lugar y pulsa en Guardar. Al regresar a la actividad anterior los
valores permanecen sin variación. Sin embargo si pulsas la tecla volver y entras a visualizar el mismo
lugar, los cambios sí que son actualizados. ¿Qué puede estar pasando?
Ejercicio paso a paso: Refrescar valores en VistaLugar tras entrar en EdicionLugar
Parece que al regresar a VistaLugar desde EdicionLugar no estamos indicando que vuelva a obtener
los datos mostrados en las vistas. Para modificar estos valores puedes tratar de hacer los siguientes
pasos:
1. En VistaLugar crea el método actualizarVistas() y mueve a este método en el código
deonCreate() que inicializa los valores de la vistas. Es decir desde TextView nombre =… hasta
el final del método.
2. En el método onCreate() realiza una llamada a este método.
3. En el método onOptionsItemSelected() reemplaza
startActivity(intent) porstartActivityForResult(intent, 1234).
4. Añade el siguiene método:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent
data) {
if (requestCode == 1234) {
actualizarVistas();
findViewById(R.id.scrollView1).invalidate();
}
}
Una vez regresamos de la actividad EdicionLugar lo que hacemos es actualizar los valores de las vistas
y forzar al sistema a que repinte la vista con id scrollView1. Esta vista corresponde
al ScrollViewque contiene todo el layout.
Añadiendo una lista de puntuaciones en Asteroides
Muchos videojuegos permiten recordar las puntuaciones de partidas anteriores, de esta forma,
un jugador puede tratar de superar su propio récord o mejorar el de otros jugadores.
En el capítulo 9 estudiaremos varios métodos para que esta información se almacene
permanentemente en el sistema. En el capítulo 10 estudiaremos como podemos compartirlo
utilizando Internet. En este capítulo nos centraremos en representar esta lista de puntuaciones
de forma atractiva utilizando la vista ListView.
Vamos a intentar que el mecanismo de acceso a esta lista de puntuaciones sea lo más
independiente posible del método final escogido. Con este propósito, vamos a definir la
interfaz AlmacenPuntuaciones.
Ejercicio paso a paso: El interfaz AlmacenPuntuaciones
1. Abre la aplicación Asteroides.
2. Pulsa con el botón derecho sobre la carpeta de código (src/org.example.asteroides) y
selecciona New > Interface.
3. En el campo Name: introduce AlmacenPuntuaciones y pulsa Finish.
4. Introduce el código que se muestra a continuación:
public interface AlmacenPuntuaciones {
public void guardarPuntuacion(int puntos,String nombre,long fecha);
public Vector<String> listaPuntuaciones(int cantidad);
}
Nota sobre Java: La interfaz es una clase abstracta pura, es decir una clase donde se
indican los métodos pero no se implementa ninguno (en este caso se dice que los métodos son
abstractos). Permite al programador de la clase establecer la estructura de esta (nombres de
métodos, sus parámetros y tipos que retorna, pero no el código de cada método). Una interfaz
también puede contener constantes, es decir campos de tipo staticy final.
Las diferentes clases que definamos para almacenar puntuaciones han de implementar
esta interfaz. Como ves tiene dos métodos. El primero para guardar la puntuación de
una partida, con los parámetros puntuación obtenida, nombre del jugador y fecha de la
partida. La segunda es para obtener una lista de puntuaciones previamente
almacenadas. El parámetro cantidad indica el número máximo de puntuaciones que
ha de devolver.
5. Veamos a continuación una clase que utiliza esta interfaz. Para ello crea en el
proyecto la claseAlmacenPuntuacionesArray.
6. Introduce el siguiente código:
public class AlmacenPuntuacionesArray implements AlmacenPuntuaciones{
private Vector<String> puntuaciones;
public AlmacenPuntuacionesArray() {
puntuaciones= newVector<String>();
puntuaciones.add("123000 Pepito Domingez");
puntuaciones.add("111000 Pedro Martinez");
puntuaciones.add("011000 Paco Pérez");
}
public void guardarPuntuacion(int puntos,
String nombre, long fecha) {
puntuaciones.add(0, puntos + " "+ nombre);
}
public Vector<String> listaPuntuaciones(int cantidad) {
return puntuaciones;
}
}
Esta clase almacena la lista de puntuaciones en un vector de String. Tiene el
inconveniente de que al tratarse de una variable local, cada vez que se cierre la
aplicación se perderán las puntuaciones. El constructor inicializa el array e introduce
tres valores. La idea es que aunque todavía no esté programado el juego y no podamos
jugar, tengamos ya algunas puntuaciones para poder representar una lista. El
método guardarPuntuacion() se limita a insertar en la primera posición del array un String
con los puntos y el nombre. La fecha no es almacenada. El
método listaPuntuaciones() devuelve el vector de String entero, sin tener en
cuenta el parámetro cantidad que debería limitar el número de Strings devueltos.
7. En la actividad Asteroides tendrás que declarar una variable para almacenar las
puntuaciones:
public static AlmacenPuntuaciones almacen=
new AlmacenPuntuacionesA
rray();
Nota sobre Java:El modificador static permite compartir el valor de una variable
entre todos los objetos de la clase. Es decir, aunque se creen varios objetos, solo existirá una
única variable almacen compartida por todos los objetos. El modificador public permite
acceder a la variable desde fuera de la clase. Por lo tanto, no será necesario crear métodos getters
y setters. Para acceder a esta variable no tendremos más que escribir el nombre de la clase
seguida de un punto y el nombre de la variable. Es decir Asteroides.almacen.
8. Para que los jugadores puedan ver las últimas puntuaciones obtenidas, modifica el
cuarto botón dellayout main.xml para que en lugar del texto “Salir” se visualice
“Puntuaciones”. Para ello modifica los ficheros res/values/strings. También sería
interesante que cambiaras el fichero res/values-en/strings.
9. Modifica el escuchador asociado al cuarto botón para que llame al método:
public void lanzarPuntuaciones(View view) {
Intent i = new Intent(this, Puntuaciones.class);
startActivity(i);
}
10. De momento no te permitirá ejecutar la aplicación. Hasta que en el siguiente
apartado no creemos la actividad Puntuaciones no será posible.
{jcomments on}
La vista ListView
Una vista ListView visualiza una lista deslizable verticalmente de varios elementos, donde cada
elemento puede definirse como un Layout .Su utilización es algo compleja, pero muy potente. Un
ejemplo lo podemos ver en la siguiente figura:
Definir un ListView conlleva los siguientes cuatro pasos:
 Diseñar un Layout que lo contenga al ListView
 Diseñar un Layout individual que se repetirá en la lista
 Implementar una actividad que lo visualice el Layout con el ListView
 Personalizar cada una de los Layouts individuales según nuestros datos
Veamos estos pasos con más detalle:
Para utilizar un ListView dentro de un Layout puedes de usar la siguiente estructura:
<FrameLayout>
<ListView
android:id="@android:id/list"... />
<TextView
android:id="@android:id/empty"
... />
</FrameLayout>
Donde tenemos un FrameLayout que permite visualizar dos posibles elementos, uno u otro, pero no los
dos simultáneamente. El primero es el ListView que se visualizará cuando haya algún elemento en la
lista. El segundo puede ser cualquier tipo de vista y se visualizará cuando no existan elementos en la
lista. El sistema controla la visibilidad de forma automática, solo has de tener cuidado de identificar cada
uno de los elementos con el valor exacto que se muestra.
NOTA: Recuerda que para crear nuevos identificadores debes utilizar la
expresión"@+id/nombre_identificador". El carácter @ significa que se trata de un identificador de recurso que
se definirá en la clase R.java. El carácter + significa que el recurso ha de ser creado en este momento. En
este caso hemos utilizado identificadores definidos en el sistema (es decir @android:significa que es un
recurso definido en la clase android.R.java).
Una vez creado el Layout que contiene el ListView tendremos que visualizarlo en una
actividad. Para este propósito utilizaremos un tipo de actividad especial, ListActivity.
También tendremos que indicar al sistema cada uno de los Layouts individuales que contendrá
el ListView. Esto lo haremos llamando al método setListAdapter(). Existen varias
alternativas con diferentes grados de dificultad. Para una mejor conprensión iremos mostrando
tres ejemplos de uso de setListAdapter(), de más sencillo a más complejo.
Las capturas anteriores muestran los tres ListView que vamos construir. El de la izquierda se limita a
mostrar una lista de Strings. El del centro visualiza una lista de un Layout diseñado por nosotros.
Aunque este Layout tiene varios componentes (una imagen y dos textos), solo cambiamos uno de los
textos. En el último ejemplo cambiaremos también la imagen de cada elemento.
video[Tutorial] Uso de ListView
Un ListView que visualiza una lista de Strings
Ejercicio paso a paso: Un ListView que visualiza una lista de Strings
1. El Layout que utilizaremos en Asteroides para mostrar las puntuaciones se
llamará puntuaciones.xml. En el se incluye una vista ListView. Crea el Layout con el siguiente código:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Puntuaciones"
android:gravity="center"
android:layout_margin="10px"
android:textSize="10pt"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false" />
<TextView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="No hay puntuaciones" />
</FrameLayout>
</LinearLayout>
2. Necesitamos ahora crear la actividad Puntuaciones para visualizar el Layout anterior. Crea una
nueva clase en tu proyecto e introduce el siguiente código:
public class Puntuaciones extends ListActivity {
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.puntuaciones);
setListAdapter(newArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
Asteroides.almacen.listaPuntuaciones(10)));
}
}
Toda actividad que vaya a visualizar un ListView ha de heredar de ListActivity. Además, ha de llamar al
método setListAdapter() para indicar el adaptadorcon la lista de elementos a visualizar. En el ejemplo se ha
utilizado una de la posibilidades más sencillas, para crear un adaptador,usar la clase ArrayAdapter<clase>.
Un ArrayAdapter crea las vistas delListView a partir de los datos almacenados en un array.Puedes utilizar
un array que contenga datos de cualquier clase, no tienes más que indicar en <Clase> la clase deseada.
En este caso se utiliza de un array de String[1]. El constructorde ArrayAdapter<clase> tiene tres parámetros:
El primer parámetro es un Context con información sobre el entorno de la aplicación. Utilizaremos como
contexto la misma actividad que hace la llamada. El segundo parámetro es un Layout, utilizado para
representar cada elemento de la lista. En este ejemplo, en lugar de definir uno nuevo,utilizaremos una ya
definido en el sistema. El último parámetro es un array con los strings a mostrar. Para ello, llamamos al
método listaPuntuaciones() que nos devuelve esta lista del objeto estático almacen de la clase Asteroides.
3. Recuerda que toda nueva actividad ha de ser registrada en AndroidManifest.xml.
4. Prueba si funcionan las modificaciones introducidas.
Un ListView que visualiza Layouts personalizados
Vamos a personalizar el ListView anterior para que cada elemento de la lista sea un Layoutdefinido por
nosotros. Para ello sigue los siguientes pasos:
Ejercicio paso a paso: Un ListView que visualiza layouts
personalizados
1. Reemplaza la clase anterior por:
public class Puntuaciones extends ListActivity {
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.puntuaciones);
setListAdapter(
new ArrayAdapter<String>(this,
R.layout.elemento_lista,
R.id.titulo,
Asteroides.almacen.listaPuntuaciones(10)));
}
}
Como hemos explicado, la clase ArrayAdapter<String> permite insertar los datos
desde un array de String en nuestro ListView. En este ejemplo se utiliza un
constructor con cuatro parámetros:
R.layout.elemento_lista: es una referencia de recurso a la vista que será utilizada
repetidas veces para formar la lista. Se define a continuación.
R.id.titulo: identifica un id de la vista anterior que ha de ser un TextView. Su texto
será reemplazado por el que se indica en el siguiente parámetro.
Asteroides.almacen.listaPuntuaciones(10): vector de String con los
textos que serán visualizados en cada uno de los TextView. Esta lista es obtenida
accediendo a la claseAsteroides a su variable estática almacen llamando a su
método listaPuntuaciones().
2. Ahora hemos de definir el Layout que representará cada uno de los elementos de la
lista. Crea el fichero res/Layout/elemento_lista.xml con el siguiente código:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight">
<ImageView android:id="@+id/icono"
android:layout_width="?android:attr/listPreferredItemHeight"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:src="@drawable/asteroide2"/>
<TextView android:id="@+id/titulo"
android:layout_width="matchl_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/icono"
android:layout_alignParentTop="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:singleLine="true" />
<TextView android:id="@+id/subtitulo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Otro Texto"
android:layout_toRightOf="@id/icono"
android:layout_below="@id/titulo"
android:layout_alignParentBottom="true"
android:gravity="center"/>
</RelativeLayout>
Este Layout representa una imagen a la izquierda con dos textos a la derecha, uno de mayor tamaño en la
parte superior. Para combinar estos elementos se ha escogido un RelativeLayout, donde el alto se establece
a partir de un parámetro de configuración del sistema ?android:attr/listPreferredItemHeight. El primer
elemento que contiene es un ImageView alineado a la izquierda. Su alto es la misma que el contenedor
(match_parent) mientras que el ancho se establece con el mismo parámetro que el alto del contenedor.Por
lo tanto la imagen será cuadrada.
3. Las imágenes utilizadas en la aplicación Asteroides puedes descargarlas de www.androidcurso.com. En el
menú El gran libro de Android / Ficheros usados en ejercicios dentro de Graficos.zip. Copia el
fichero asteriode1.png, asteriode2.png y asteriode3.png a la carpeta res/drawable.
4. Ejecuta la aplicación y verifica el resultado.
Un ListView con nuestro propio adaptador
En el ejercicio anterior hemos visto como podíamos asociar un Layout definido por nosotros
alListView y personalizar uno de sus campos. Si queremos algo más adaptable,por ejemplo cambiar
varios campos, tendremos que escribir nuestro propio adaptador extendiendo la clase BaseAdapter.
En esta clase habrá que sobreescribir los siguientes cuatro métodos:
View getView(int position, View convertView, ViewGroup parent)
Este método ha de construir un nuevo objeto View que será visualizado en la posición position .
Opcionalmente podemos partir de una vista base convertView para generar más rápido este objeto.
El último parámetro corresponde al contenedor de vistas donde el objeto va a ser añadido.
int getCount()
Devuelve el número de elementos de la lista.
Object getItem(int position)
Devuelve el elemento en una determinada posición de la lista.
long getItemId(int position)
Devuelve el identificador de fila de una determinada posición de la lista.
Veamos un ejemplo:
Ejercicio paso a paso: Un ListView con nuestro propio adaptador
1. Crea la clase MiAdaptador.java en el proyecto con el siguiente código:
public class MiAdaptador extends BaseAdapter {
privatefinal Activity actividad;
privatefinal Vector<String> lista;
public MiAdaptador(Activity actividad, Vector<String> lista) {
super();
this.actividad = actividad;
this.lista= lista;
}
public View getView(int position, View convertView,
ViewGroup parent) {
LayoutInflater inflater = actividad.getLayoutInflater();
View view = inflater.inflate(R.layout.elemento_lista, null,
true);
true);
TextView textView =(TextView)view.findViewById(R.id.titulo);
textView.setText(lista.elementAt(position));
ImageView imageView=(ImageView)view.findViewById(R.id.icono);
switch (Math.round((float)Math.random()*3)){
case 0:
imageView.setImageResource(R.drawable.asteroide1);
break;
case 1:
imageView.setImageResource(R.drawable.asteroide2);
break;
default:
imageView.setImageResource(R.drawable.asteroide3);
break;
}
return view;
}
public int getCount() {
return lista.size();
}
public Object getItem(int arg0) {
return lista.elementAt(arg0);
}
public long getItemId(int position) {
return position;
}
}
2. En el constructor de la clase se indica la actividad donde se ejecutará y la lista de
datos a visualizar. El método más importante de esta clase es getView() el cual tiene
que construir los diferentes Layouts que serán añadidos en la lista. Comenzamos
construyendo un objeto View a partir del código xml definido enelemento_lista.xml. Este
trabajo se realiza por medio de la clase LayoutInflater.Luego, se modifica el texto
de uno de los TextView según el array que se pasó en el constructor. Finalmente, se
obtiene un número al azar (Math.round()) y se asigna uno de los tres gráficos de
forma aleatoria.
3. Reemplaza en la clase Puntuaciones la llamada al constructor
de ArrayAdapter<String> por:
setListAdapter(new MiAdaptador(this,
Asteroides.almacen.listaPuntuaciones(10)));
4. Ejecuta la aplicacióny verifica el resultado.
NOTA: En algunos casos el adaptador ha de trabajar con listas muy grandes o estas listas han
de ser creadas desde un servidor. En estos casos es mejor ir solicitando la información a medida
que se va representando. Un ejemplo se muestra en la aplicación ApiDemos descrita en el
capítulo 1, en la actividad:
com.example.android.apis.view.List13
Detectar una pulsación sobre un elemento de la lista
Un ListView puede tener diferentes componentes que nos permitan interaccionar con el
usuario. Por ejemplo, cada elemento definido en getView() puede tener botones para
diferentes acciones.
Hay un tipo de interacción muy sencilla de definir. La clase ListActivity tiene un método
que es invocado cada vez que se pulsa sobre un elemento de la lista. El siguiente ejercicio
ilustra cómo utilizarlo.
Ejercicio paso a paso: Detectar una pulsación sobre un elemento de
la lista
1. Añade el siguiente método a la clase Puntuaciones.java:
@Override protected void onListItemClick(ListView listView,
View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
Object o = getListAdapter().getItem(position);
Toast.makeText(this, "Selección: " + Integer.toString(position)
+ " - " + o.toString(),Toast.LENGTH_LONG).show();
}
2. Ejecuta la aplicación, pulsa en “Puntuaciones” y luego en una puntuaciób para verificarel
resultado.
Las intenciones
Una intención representa la voluntad de realizar alguna acción o tarea; como realizar una
llamada de teléfono o visualizar una página web. Una intención nos permite lanzar una
actividad o servicio de nuestra aplicación o de una aplicación diferente.
video[Tutorial] Las intenciones en Android
Existen dos tipos de intenciones:
 Intenciones explícitas: se indica exactamente el componente a lanzar. Su utilización
típica es la de ir ejecutando los diferentes componentes internos de una aplicación. Por
ejemplo, desde la actividadAsteroides lanzamos AcercaDe por medio de una intención
explicita.
 Intenciones implícitas: pueden solicitar tareas abstractas, como “quiero tomar una
foto” o “quiero enviar un mensaje”. Además las intenciones se resuelven en tiempo de
ejecución, de forma que el sistema mirará cuantos compomentes han registrado la
posibilidad de ejecutar ese tipo deintención. Si encuentra varias el sistema puede
preguntar al usuario el comomente que prefiere utilizar.
Además, como se ha estudiado en el apartado Comunicación entre actividades las intenciones ofrecen
un servicio de paso de mensajes que permite interconectar datos entre componentes.
En concreto se utilizan intenciones cada vez que queramos:
 lanzar una actividad (startActivity() y startActivityForResult())
 lanzar un servicio (startService())
 lanzar un anuncio de tipo broadcast (sendBroadcast())
 conectarnos con un servicio (bindService())
En muchas ocasiones una intención no será inicializada por la aplicación, si no por el sistema,
por ejemplo, cuando pedimos visualizar una página Web. En otras ocasiones será necesario
que la aplicación inicialice su propia intención. Para ello se creará un objeto de la clase Intent.
Cuando se crea una Intención (es decir, se instancia un objeto de tipo Intent) esta contiene
información de interés para que el sistema trate adecuadamente la intención o para el
componente que recibe la intención. Puede incluir la siguiente información:
Nombre del componente: Identificamos el componente que queremos lanzar con la
intención. Podemos utilizar el nombre de clase totalmente cualificado
(org.example.asteroides.AcercaDe) que queremos lanzar. El nombre del
componente es opcional. En caso de no indicarse se utilizará otra información de la
intención para obtener el componente a lanzar. A este tipo de intenciones se les
conocía como intenciones explícitas.
Acción: Una cadena de caracteres donde indicamos la acción a realizar (o en caso de
un Receptor de anuncios (Broadcast receiver)la acción que tuvo lugar y queremos reportar).
La clase Intent define una serie de constantes para acciones genéricas que son
listadas a continuación. No obstante, además de estas podemos definir nuevas
acciones:
Constante
componente
a lanzar
Acción
ACTION_CALL Actividad Inicializa una llamada de teléfono.
ACTION_EDIT Actividad Visualiza datos paraque el usuario los edite.
ACTION_MAIN Actividad
Arranca como actividad principal de una tarea
(sin datos de entrada y sin devolver datos)
ACTION_SYNC Actividad
Sincroniza datos en un servidor con los datos
un dispositivo móvil.
ACTION_BATTERY_LOW receptor de anuncios Advertencia de bateria baja.
ACTION_HEADSET_PLUG receptor de anuncios
Los auriculares han sido conectados o
desconectados.
ACTION_SCREEN_ON receptor de anuncios La pantalla es activada.
ACTION_TIMEZONE_CHANGED receptor de anuncios Se cambia la selección de zona horaria.
Tabla 3: Algunas acciones estándar de las Intenciones
También puedes definir tus propias acciones. En este caso has de indicar el paquete de tu
aplicación como prefijo. Por ejemplo:
org.example.asteroides.MUESTRA_PUNTUACIONES.
Categoría: Complementa a la acción. Indica información adicional sobre el tipo de
componente que ha de ser lanzado. El número de categorías puede ser arbitrariamente
ampliado. No obstante, en la clase Intent se definen una serie de categorías genéricas
que podemos utilizar.
Constante Significado
CATEGORY_BROWSABLE
La actividad lanzada puede ser con seguridad invocada por
el navegador para mostrar los datos referenciados por un
enlace - por ejemplo, una imagen o un mensaje de correo
electrónico.
CATEGORY_HOME
La actividad muestra la pantalla de inicio,la primera
pantalla que ve el usuario cuando el dispositivo está
encendido o cuando la tecla HOME es presionada.
CATEGORY_LAUNCHER
La actividad puede ser la actividad inicial de una tarea y se
muestra en el lanzador de aplicaciones de nivel superior.
CATEGORY_PREFERENCE La actividad a lanzar es un panel de preferencias.
Tabla 4: Categorías estándar de las Intenciones
Una categoría suele utilizarse junto con una acción para aportar información adicional. Por ejemplo,
indicaremos ACTION_MAIN a las actividades que pueden utilizarse como puntos de entrada de
una aplicación. Indicaremos además CATEGORY_LAUNCHER para que la actividad sea mostrada en
la pantalla de inicio.
Datos: Referencia a los datos con los que trabajaremos. Hay que expresar estos datos por medio de
una URI (el mismo concepto ampliamente utilizado en Internet). Ejemplos de URIs
son: tel:963228525,http://www.androidcurso.com, content://call_log/calls… En muchos casos resulta
importante saber el tipo de datos con el que se trabaja. Con este propósito se indica el tipo MIME
asociado a la URI, es decir, se utiliza el mismo mecanismo que en Internet. Ejemplos de tipos MIME
son text/xml, image/jpeg, audio/mp3…
Extras: Información adicional que será recibida por el componente lanzado. Está formada por un
conjunto de pares variable/valor. Estas colecciones de valores se almacenan en un objeto de la
clase Bundle. Su utilización ha sido descrita en la sección Comunicación entre actividades.
Recordemos cómo se introducían estos valores en un Intent.
intent.putExtra("usuario", "Pepito Perez");
intent.putExtra("edad", 27);
En el apartado Creación de nuevas actividades aprendimos a lanzar una actividad de forma
explícita utilizando el constructor Intent(Context contexto, Class<?> clase). Por
ejemplo, para lanzar la actividad AcercaDeescribíamos:
Intent intent = new Intent(this, AcercaDe.class);
startActivity(intent);
Para lanzar una actividad de forma implícita podemos usar el
constructor Intent(String action, Uri uri). Por ejemplo:
Intent intent = new Intent(Intent.ACTION_DIAL,
URI.parse("tel:962849347");
startActivity(intent);
También se puede utilizar startActivityForResult() si esperamos que la actividad nos
devuelva datos.
Ejercicio paso a paso: Uso de intenciones implícitas
1. Crea un nuevo proyecto con nombre Intenciones.
2. El Layout de la actividad inicial ha de estarformado por cinco botones,taly como se muestra a continuación:
3. Abre la actividad principal e incorpora los siguientes métodos:
public void pgWeb(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.androidcurso.com/"));
startActivity(intent);
}
public void llamadaTelefono(View view) {
Intent intent = new Intent(Intent.ACTION_CALL,
Uri.parse("tel:962849347"));
startActivity(intent);
}
public void googleMaps(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("geo:41.656313,-0.877351"));
startActivity(intent);
}
public void tomarFoto(View view) {
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivity(intent);
}
public void mandarCorreo(View view) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, "asunto");
intent.putExtra(Intent.EXTRA_TEXT, "texto del correo");
intent.putExtra(Intent.EXTRA_EMAIL,
new String[] {"jtomas@upv.es" });
startActivity(intent);
}
.
4. Asocia el atributo onClick de cada uno de los botones al método correspondiente.
5. Abre AndroidManifest.xml e inserta la siguiente línea al final, antes de </manifest>:
<uses-permission android:name="android.permission.CALL_PHONE"/>
NOTA: En el CAPÍTULO 7 se estudiará el tema de la seguridad.Aprenderás como has de solicitar el
permiso adecuado si quieres que tu aplicación llame por teléfono o acceda a Internet.Cuando estas
acciones no las realizas directamente, si no que las pides a través de una intención,no es tu
aplicación quien las realiza y por tanto no has de pedir estos permisos. La única excepción es el caso
de realizar una llamada de teléfono.Para poder realiza una llamada de teléfono desde una intención
si que hay que pedir el permiso correspondiente.
6. Si ejecutas esta aplicación en un emulador es muy posible que el botón mandar Correo o Google Maps no
funcione. La razón es que no hay ninguna aplicación instalada en el emulador que sea capaz de realizar
este tipo de acciones. Si tienes estos problemas, Abre el AVD Manager y crea un dispositivo virtual con
Google API. Estos dispositivos incorporan además de las API de Android, algunas de las API de Google,
como la de Google Maps (Estas API se estudiarán más adelante).
7. Ejecuta la aplicación en un terminal real. Observa como el botón mandar Correo te permite seleccionar
entre diferentes aplicaciones con esta funcionalidad.
8. Este resultado puede variar en función de las aplicaciones instaladas.
Recursos adicionales: Tabla con intenciones que podemos utilizar
de aplicaciones Google
Aplicación URI Acción Resultado
Navegador
Web
http://dirección_web
https://dirección_web
VIEW
Abre una ventana de navegador con una
URL.
"" (cadena vacía)
http://dirección_web
https://dirección_web
WEB_SEARCH
Abre el fichero en la ubicación indicada en
el navegador.
Teléfono
tel:número_teléfono CALL
Realiza una llamada de teléfono. Los
números validos se definen enIETF RFC
3966 . Ejem.tel:2125551212.. Necesitamos
el permiso
android.permission.CALL_PHONE
tel:número_teléfono
voicemail:
DIAL
Introduce un número en la aplicación
Teléfono, sin llegar a realizar la llamada.
No necesita permiso.
Google
Maps
geo:latitud,longitud
geo:lat,long?z=zoom
geo:0,0?q=dirección
geo:0,0?q=búsqueda
VIEW
Abre la aplicación Google Maps para una
localización determinada. El campo z
específica el nivel de zoom.
Google
Streetview
google.streetview:
cbll=latitud,longitud&
cbp=1,yaw,,pitch,zoom&
mz=mapZoom
VIEW
Abre la aplicación Street View para la
ubicación dada. El esquema de URI se
basa en la sintaxis que utiliza Google
Maps. Solo el campo cbll es obligatorio.
Práctica: Uso de intenciones implícitas
1. Crea nuevos botones en la aplicación del ejercicio anterior y experimenta con otro
tipo de acciones y URls. Puedes consultar la tabla anterior. A continuación tienes
algunas propuestas:
2. Compara las acciones VIEW y WEB_SEARCH. ¿Encuentras alguna diferencia?
3. Compara las acciones CALL y DIAL. ¿Encuentras alguna diferencia?
4. Experimenta con Google Streetview
La etiqueta <intent-filter>
Cuando creamos una nueva actividades, servicios o receptor broadcast podemos informar al
sistema que tipo de intenciones implícitas pueden ser resultas con nuestro componente. Para
conseguir esto utilizaremos la etiqueta<intent-filter> de AndroidManifest.xml.
Cuando desarrollamos una aplicación lo habitual es utilizar intenciones explicitas, que son resueltas
utilizando el nombre de la clase. Por lo tanto, si vamos a llamar a nuestro componente de forma
explicita, no tiene sentido crear un filtro de intenciones.

Más contenido relacionado

PPTX
Mooc smm substructure_2
PDF
EIPSI-UAB_FORMACIO DIFUSIO SGIE-NLG-FBM.pdf
PDF
análisis vial básico Huechuraba
PDF
Manual programación android
PDF
Resumen el gran libro de andorid
DOCX
Estructura general de una app
PPTX
Taller android parte1 - Android Developers Loja Group
DOCX
Elementos de eclipse
Mooc smm substructure_2
EIPSI-UAB_FORMACIO DIFUSIO SGIE-NLG-FBM.pdf
análisis vial básico Huechuraba
Manual programación android
Resumen el gran libro de andorid
Estructura general de una app
Taller android parte1 - Android Developers Loja Group
Elementos de eclipse

Similar a Manual android (20)

DOCX
Elementos de eclipse
PPTX
Estructura de un proyecto android
PDF
LIBRO DE ANDROID
PPTX
Programacion orientada a objetos Java
PPTX
tutorial de eclipse
PPTX
Proyectoytzelyalonso (1)
PPTX
Clases de Programación Android
PPTX
TUTORIAL DE ECLIPSE
ODT
Materiaeloy
PPTX
Sesión 04 - Aplicaciones móviles ATI.pptx
PPTX
Introducción a Android
PPTX
Como insertar una imagen
PPTX
Instrucciones y estructuras
PPTX
Como insertar una imagen
PPTX
Como insertar una imagen en eclipse java
PDF
Tutorial de ReactJS.pdf completo para principiantes
DOCX
Investigacion para agregar una imagen a eclipse
DOCX
Investigacion para agregar una imagen a eclipse
PPTX
Manual de eclpse emrt
PPTX
como insertar imagen a una aplicación android de java.
Elementos de eclipse
Estructura de un proyecto android
LIBRO DE ANDROID
Programacion orientada a objetos Java
tutorial de eclipse
Proyectoytzelyalonso (1)
Clases de Programación Android
TUTORIAL DE ECLIPSE
Materiaeloy
Sesión 04 - Aplicaciones móviles ATI.pptx
Introducción a Android
Como insertar una imagen
Instrucciones y estructuras
Como insertar una imagen
Como insertar una imagen en eclipse java
Tutorial de ReactJS.pdf completo para principiantes
Investigacion para agregar una imagen a eclipse
Investigacion para agregar una imagen a eclipse
Manual de eclpse emrt
como insertar imagen a una aplicación android de java.
Publicidad

Último (8)

PDF
AutoCAD Herramientas para el futuro, Juan Fandiño
PDF
simulacion de teoria de control para maquinas
PPTX
Derechos_de_Autor_y_Creative_Commons.pptx
DOCX
trabajo programacion.docxxdxxxddxdxxdxdxxxdxxdxdxd
PPTX
sistemas de informacion.................
PDF
Su punto de partida en la IA: Microsoft 365 Copilot Chat
PDF
modelos de control para sistemas digitales
PDF
DIMENSIONADO DE UNA INSTALACION FOTOVOLTAICA.pdf
AutoCAD Herramientas para el futuro, Juan Fandiño
simulacion de teoria de control para maquinas
Derechos_de_Autor_y_Creative_Commons.pptx
trabajo programacion.docxxdxxxddxdxxdxdxxxdxxdxdxd
sistemas de informacion.................
Su punto de partida en la IA: Microsoft 365 Copilot Chat
modelos de control para sistemas digitales
DIMENSIONADO DE UNA INSTALACION FOTOVOLTAICA.pdf
Publicidad

Manual android

  • 1. Unidad 2. Diseño de la interfaz de usuario: Vistas y Layouts Introducción El diseño de la interfaz de usuario cobra cada día más importancia en el desarrollo de una aplicación. La calidad de la interfaz de usuario puede ser uno de los factores que conduzca al éxito o al fracaso de todo el proyecto. Si has realizado alguna aplicación utilizando otras plataformas, advertirás que el diseño de la interfaz de usuario en Android sigue una filosofía muy diferente. En Android la interfaz de usuario no se diseña en código, sino utilizando un lenguaje de marcado en XML similar al HTML. A lo largo de este capítulo mostraremos una serie de ejemplos que te permitirán entender el diseño de la interfaz de usuario en Android. Aunque no será la forma habitual de trabajar, comenzaremos creando el interfaz de usuario mediante código. De esta forma comprobaremos como cada uno de los elementos del interfaz de usuario (las vistas) realmente son objetos Java. Continuaremos mostrando cómo se define el interfaz de usuario utilizando código XML. Pasaremos luego a ver las herramientas de diseño integradas en Eclipse. Se describirá el uso de Layouts que nos permitirá una correcta organización de las vistas y como el uso de recursos alternativos nos permitirá adaptar nuestra interfaz a diferentes circunstancias y tipos de dispositivos. En este capítulo también comenzaremos creando la aplicación de ejemplo desarrollada a lo largo del curso, Asteroides. Crearemos la actividad principal, donde simplemente mostraremos cuatro botones, con los que se podrán arrancar diferentes actividades. A continuación aprenderemos a crear estilos y temas y los aplicaremos a estas actividades. Para terminar la unidad propondremos varias prácticas para aprender a utilizar diferentes tipos de vistas y Layouts. Objetivos  Entender cómo se realiza el diseño del interfaz de usuario en una aplicación Android.  Aprender a trabajar con vistas y mostrar sus atributos más importantes.  Enumerar los tipos de Layouts que nos permitirán organizar las vistas.  Mostrar cómo se utilizan los recursos alternativos.  Aprenderemos a crear estilos y temas para personalizar nuestras aplicaciones.  Mostrar cómo interactuar con las vistas desde el código Java  Describir el uso de layouts basados en pestañas (tabs). Creación de una interfaz de usuario por código Veamos un primer ejemplo de cómo crear una interfaz de usuario utilizando exclusivamente código Java. Esta no es la forma recomendable de trabajar con Android, sin embargo resulta interesante para resaltar algunos conceptos.
  • 2. Ejercicio paso a paso: Creación del interfaz de usuario por código 1. Abre el proyecto HolaMundo creado en el capítulo anterior y visualiza MainActivity.java. 2. Comenta la última sentencia del método onCreate() añade las tres que se muestran a continuación en negrita: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); TextView texto = new TextView(this); texto.setText("Hello, Android"); setContentView(texto); } Nota sobre Java: Para poder utilizar el objeto TextView has de importar un nuevo paquete, para ello añade al principio “import android.widget.TextView;”. Otra alternativa es pulsar Ctrl-Shift-O, para que se añadan automáticamente los paquetes que faltan. La interfaz de usuario de Android está basada en una jerarquía de clases descendientes de la clase View(vista). Una vista es un objeto que se puede dibujar y se utiliza como un elemento en el diseño de la interfaz de usuario (un botón, una imagen, una etiqueta de texto como en el utilizado en el ejemplo,…). Cada uno de estos elementos se define como una subclase de la clase View; la subclase para representar un texto es TextView. El ejemplo comienza creando un objeto de la clase TextView. El constructor de la clase acepta como parámetro una instancia de la clase Context (contexto). Un contexto es un manejador del sistema que proporciona servicios como la resolución de recursos, obtención de acceso a bases de datos o preferencias. La claseActivity es una subclase de Context, y como la clase MainActivity es una subclase de Activity, también es tipo Context. Por ello, puedes pasar this (el objeto actual de la clase MainActivity) como contexto delTextView. 3. Después se define el contenido del texto que se visualizará en el TextView mediante setText(). Finalmente, mediante setContentView()se indica la vista utilizada por la actividad. 4. Ejecuta el proyecto para verificar que funciona. Creación de una interfaz de usuario usando XML En el ejemplo anterior hemos creado la interfaz de usuario directamente en el código. A veces puede ser muy complicado programar interfaces de usuario, ya que pequeños cambios en el diseño pueden corresponder a complicadas modificaciones en el código. Un principio
  • 3. importante en el diseño de software es que conviene separar todo lo posible el diseño, los datos y la lógica de la aplicación. Android proporciona una alternativa para el diseño de interfaces de usuario: los ficheros de diseño basados en XML. Veamos uno de estos ficheros. Para ello accede al fichero res/layout/activity_main.xml de nuestro proyecto. Se muestra a continuación. Este layout o fichero de diseño proporciona un resultado similar que el ejemplo de diseño por código anterior: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout> NOTA: Cuando haces doble clic en el Package Explorer sobre activity_main.xml, probablemente lo abra en modo Graphical Layout. Para verlo en modo texto selecciona la pestaña activity_main.xml. Resulta sencillo interpretar su significado. Se introduce un elemento de tipo RelativeLayout, como se estudiará más adelante su función es contener otros elementos de tipo View. Este RelativeLayout tiene cinco atributos. Los dos primeros, xmlns:android,y xmlns:tools son declaraciones de espacios de nombres de XML que utilizaremos en este fichero (este tipo de parámetro solo es necesario especificarlo en el primer elemento). Los dos siguientes permiten definir el ancho y alto de la vista. En el ejemplo se ocupará todo el espacio disponible. El último atributo indica la actividad asociada a este Layout. Dentro del RelativeLayout solo tenemos un elemento de tipo TextView. Este dispone de tres atributos. Los dos primeros definen el ancho y alto (se ajustará al texto contenido). El último indica el texto a mostrar. No se ha indicado un texto directamente sino una referencia, "@string/hello_world". Esta referencia ha de estar definida en el fichero res/values/strings.xml. Si abres este fichero, tienes el siguiente contenido: <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Hola Mundo</string> <string name="hello_world">Hello world!</string> <string name="menu_settings">Settings</string> </resources> Esta es la práctica recomendada en Android para la inserción de textos en tu aplicación, dado que facilita su localización a la hora de realizar la traducción a otros idiomas. Es decir,
  • 4. utilizaremos los ficheros layout para introducir el diseño de los interfaces y el fichero strings para introducir los textos utilizados en los distintos idiomas. Ejercicio paso a paso: Creación del Interfaz de usuario con XML 1. Para utilizar el diseño en XML regresa al fichero MainActivity.java y deshaz los cambios que hicimos antes (elimina las tres últimas líneas y quita el comentario). @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } 2. Ejecuta la aplicación y verifica el resultado. Ha de ser muy similar al anterior. 3. Modifica elvalor de hello_world en el fichero res/values/strings.xml. 4. Vuelve a ejecutar la aplicación y visualiza el resultado. Analicemos ahora la línea en la que acabas de quitar el comentario: setContentView(R.layout.activity_main) ; Aquí, R.layout.main corresponde a un objeto View que será creado en tiempo de ejecución a partir del recurso activity_main.xml. Trabajar de esta forma, en comparación con el diseño basado en código, no quita velocidad y requiere menos memoria. El plug-in de Eclipse crea automáticamente este identeficador en la clase R del proyecto a partir de los elementos de la carpeta res. La definición de la clase R puede ser similar a: public final class R { public static final class attr { } public static final class drawable { public static final int ic_launcher=0x7f020000; } public static final class id { public static final int menu_settings=0x7f070000; } public static final class layout { public static final int activity_main=0x7f030000; } public static final class menu { public static final int activity_main=0x7f060000; } public static final class string { public static final int app_name=0x7f040000; public static final int hello_world=0x7f040001; ...
  • 5. NOTA: Este fichero se genera automáticamente. Nunca debes editarlo. Has de tener claro que los identificadores de la clase R son meros números que informan al gestor de recursos, que datos ha de cargar. Por lo tanto no se trata de verdaderos objetos, estos serán creados en tiempo de ejecución solo cuando sea necesario usarlos. Ejercicio paso a paso: El fichero R.java. 1. Abre el fichero llamado gen/com.example.holamundo/R.java de tu aplicación. 2. Comparalo con el fichero mostrado previamente. ¿Qué diferencias encuentras? (RESPUESTA: los valores numéricos en hexadecimal) 3. Abre el fichero MainActivity.java y reemplaza R.layout.activity_main por el valor numérico al que corresponde en R.java. 4. Ejecuta de nuevo el proyecto. ¿Funciona? ¿Crees que sería adecuado dejar este valor numérico? 5. Aunque haya funcionado, este valor puede cambiar en un futuro. Por lo tanto para evitar problemas futuros vuelve a reemplazarlo por R.layout.activity_main. Edición visual de las vistas Veamos ahora como editar los layouts o ficheros de diseño en XML. En el explorador de paquetes abre el ficherores/layout/ activity_main.xml. Verás que en la parte inferior de la ventana central aparecen dos lengüetas:Graphical Layout y activity_main.xml. El plug-in de Android te permite dos tipos de diseño: editar directamente el código XML (lengüeta activity_main.xml) o realizar este diseño de forma visual (lengüeta Grafical Layout). (### typo in English text: “Grapical”). Veamos cómo se realizaría el diseño visual:
  • 6. En el marco derecho se visualiza una lista con todos los elementos del layout. Este layout tiene solo dos vistas: un RelativeLayout conteniendo un TextView. En este momento solo hay dos un RelativeLayoutque contiene un TextView. En el marco central aparece una representación de cómo se verá el resultado. En la parte superior aparecen varios controles para representar esta vista en diferentes configuraciones. Cuando diseñamos una vista en Android, hay que tener en cuenta que desconocemos el dispositivo final donde será visualizada y la configuración específica elegida por el usuario. Por esta razón, resulta importante que verifiques que la vista se ve de forma adecuada en cualquier configuración. En la parte superior, de izquierda a derecha, encontramos los siguientes botones: opciones de previsualización en fase de diseño, tipo de dispositivo (tamaño y resolución de la pantalla), orientación horizontal (landscape) o vertical (portrait), cómo se verá nuestra vista tras aplicar un tema, la actividad asociada, la configuración regional (locale), la versión de Android. Para editar un elemento selecciónalo en el marco de la derecha (Outline) o pincha directamente sobre él en la ventana de previsualización. Al seleccionarlo puedes modificar alguna de sus propiedades en el marco Propertiessituado debajo de Outline. Da un vistazo a las propiedades disponibles para TextView y modifica alguna de ellas. En muchos casos te aparecerá un desplegable con las opciones disponibles. El marco de la izquierda te permite insertar de forma rápida nuevas vistas al layout. Puedes arrastrar cualquier elemento a la ventana de previsualización o al marco Outline. En el anexo B se ha incluido un listado con las vistas disponibles. video[Tutorial] Diseño visual de Layouts: Visión general Ejercicio paso a paso: Creación visual de Vistas 1. Crea un nuevo proyecto con nombre PrimerasVistas. Puedes dejar el resto de parámetros con los valores por defecto. 2. Abre el fichero res/layout/activity_main.xml. 3. En el marco Outline pulsa con el botón derecho sobre RelativeLayout y selecciona Change Layout…Selecciona LinearLayout (Vertical). Este tipo de layout es uno de los más sencillos de utilizar. Te permite representar las vistas una debajo de la otra.. 4. Desde la paleta de izquierda arrastra los siguientes elementos: ToggleButton, CheckBox, ProgressBar(Large)y RatingBar. 5. Selecciona la primera vista que estaba ya creada (TextView) y pulsa el botón <Supr> para eliminarla. 6. Pulsa el primer botón (Set Horizontal Orientation) para conseguir que el LinearLayout donde están las diferentes vistas tenga una orientación horizontal. Comprobarás que no caben todos los elementos. 7. Pulsa el siguiente botón (Set Vertical Orientation) para volver a una orientación vertical.
  • 7. 8. Selecciona la vista ToggleButton. Pulsa el botón siguiente al que acabamos de utilizar (Toggle Fill Width). Conseguirás que el ancho del botón se ajuste al ancho de su contenedor. 9. Pulsa el botón siguiente (Troggle Fill Height). Conseguirás que el alto del botón se ajuste al alto de su contenedor. El problema es que el resto de elementos dejan de verse. Vuelve a pulsar este botón para regresar a la configuración anterior (También puedes pulsar Ctrl-z). 10. Selecciona la vista CheckBox. Pulsa el botón siguiente al que acabamos de utilizar(Change Margins…) para introducir un margen en la vista. En la entrada All introduce “20dp”. 11. Pulsa el botón siguiente(Change Gravity) y selecciona Center Horizontal. 12. Observa como hay un espacio sin usar en la parte inferior del Layout. Pulsa el botón siguiente(Distribute Weights Evenly). El alto de las vistas se ajustará para que ocupen la totalidad del Layout. Realmente lo que hace es dividir el espacio sin usar de forma proporcional entre las vistas. Es equivalente a poner Layout Weights =1 para todas las vistas de este Layout. Esta propiedad será modificada en un siguiente punto. 13. Con la vista CheckBox selecccionada, pulsa el botón (Assign All Weight) para asignar todo el alto restante a la vista seleccionada. 14. Pulsa el botón siguiente(Change Layout Weight) e introduce el valor 2. Selecciona la vistaToggleButton y usando este mismo botón, introduce el valor 0.5. Selecciona la vista ProgressBar e introduce el valor 4. Como puedes observar estos pesos permiten repartir el alto sobrante entre las vistas. 15. Utiliza los siguientes botones para ajustar el zoom. 16. Utiliza los botones de la barra superior para observar cómo se representará el Layout en diferentes situaciones y tipos de dispositivos: 17. Selecciona la vista CheckBox y observa las diferentes propiedades que podemos definir. Algunas ya han sido definidas por medio de la barra de botones. En concreto y siguiendo el mismo orden que en los botones hemos modificado: Layout width = wrap_content, Layout height = wrap_content, Layout margin = 20dp, Layout gravity = center_horizontal y Layout weight = 2. 18. Busca la propiedad Text y sustituye el valor “CheckBox” por “Guardar automáticamente” y Text size por “9pt”. 19. El resultado final obtenido se muestra a continuación:
  • 8. Los pequeños triangulos amarillos son advertencias(warnings), donde se nos dan sugerencias para relizar un diseño correcto. Trata de eliminar alguna de estas advertencias. (Solución: Defir los textos usados como recursos en res/values/strings.xml y referenciar estos recursos en el atributoandroid:textcomo: android:text="@string/nombretexto"). 20. Pulsa sobre la lengüeta de la parte inferior con nombre activity_main.xml. Pulsa las teclas Shift-Ctrl-fpara que formatee adecuadamente el código XML. Este código se muestra a continuación. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <ToggleButton android:id="@+id/toggleButton1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.5" android:text="ToogleButton" /> <CheckBox android:id="@+id/checkBox1" android:layout_width=""wrap_content" android:layout_height="0dp" android:layout_gravity="center_horizontal"
  • 9. android:layout_weight="2" android:text="Guardar automáticamente" android:textSize="9pt" /> <ProgressBar android:id="@+id/progressBar1" style="?android:attr/progressBarStyleLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="4" /> <RatingBar android:id="@+id/ratingBar1" android:layout_width="wrap_content" android:layout_height="wrap_content" </LinearLayout> Observa como el entorno subraya las líneas donde hay advertencias (warnings) en amarillo. Por ejemplo, nos indica que es preferible introducir los textos como recursos. 21. Ejecuta el proyecto para ver el resultado en el dispositivo. Ejercicio paso a paso: Vistas de entrada de texto 1. Añade en la parte superior del Layout anterior una vista de tipo entrada de texto EditText, de tipo normal ( Plain Text). Debajo de esta una de tipo nombre y apellido (Person Name) seguida de una de tipo palabra secreta (Password). Continua así con otros tipos de entradas de texto. 2. Ejecuta la aplicación. 3. Observa, como al introducir el texto de una entrada se mostrará un tipo de teclado diferente. Los atributos de las vistas video[Tutorial] Atributo de la clase View en Android video[Tutorial] Atributo de la clase TexView en Android
  • 10. Recursos adicionales: Atributos de dimensión En muchas ocasiones tenemos que indicar el ancho o alto de una vista, un margen, el tamaño de un texto o unas coordenadas. Este tipo de atributos se conocen como atributos de dimensión. Dado que nuestra aplicación podrá ejecutarse en gran variedad de dispositivos con resoluciones muy diversas, Android nos permite indicar estas dimensiones de varias formas. En la siguiente tabla se muestran las diferentes posibilidades: px (píxeles): Estas dimensiones representan los píxeles en la pantalla. mm (milímetros): Distancia real medida sobre la pantalla. in (pulgadas): Distancia real medida sobre la pantalla. pt (puntos): Equivale a 1/72 pulgadas. dp o dip (píxeles independientes de la densidad): Presupone un dispositivo de 160 píxeles por pulgada. Si luego el dispositivo tiene otra densidad, se realizará la correspondiente regla de tres. Cuando sea representado en dispositivos con una densidad grafica diferente, este hara un recalculado de forma que se conserve la misma medida midiendo sobre la pantalla dispositivo. Es decir 160dpequivaldrá siempre a una pulgada en cualquier tipo de dispositivo. Por lo tanto, se trata de una medida real sobre pantalla equivalente a 1/160 pulgadas. sp (píxeles escalados): Similar a dp pero también se escala en función del tamaño de fuente que el usuario ha escogido en las preferencias. Indicado cuando se trabaja con fuentes. Recursos adicionales:Tipos de vista y sus atributos Consulta el Anexo B del libro para conocer una lista con todos las descendientes de la clase View y sus atributos. Layouts
  • 11. Si queremos combinar varios elementos de tipo vista tendremos que utilizar un objeto de tipo Layout. Un Layoutes un contenedor de una o más vistas y controla su comportamiento y posición. Hay que destacar que un Layoutpuede contener a otro Layout y que es un descendiente de la clase View. La siguiente lista describe los Layout más utilizados en Android: LinearLayout: Dispone los elementos en una fila o en una columna. TableLayout: Distribuye los elementos de forma tabular. RelativeLayout: Dispone los elementos en relación a otro o al padre. AbsoluteLayout: Posiciona los elementos de forma absoluta. FrameLayout: Permite el cambio dinámico de los elementos que contiene. Dado que un ejemplo vale más que mil palabras, pasemos a mostrar cada uno de estos layouts en acción: LinearLayout es uno de los Layout más utilizado en la práctica. Distribuye los elementos uno detrás de otro, bien de forma horizontal o vertical. <LinearLayout xmlns:android="http://... android:layout_height="match_parent" android:layout_width="match_parent" android:orientation ="vertical"> <AnalogClock android:layout_width="wrap_content" android:layout_height="wrap_content"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un checkBox"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
  • 12. android:text="Un botón"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un texto cualquiera"/> </LinearLayout> TableLayoutdistribuye los elementos de forma tabular. Se utiliza la etiqueta TableRowcada vez que queremos insertar una nueva línea. <TableLayout xmlns:android=”http://... android:layout_height="match_parent" android:layout_width="match_parent"> <TableRow> <AnalogClock android:layout_width="wrap_content" android:layout_height="wrap_content"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un checkBox"/> </TableRow> <TableRow> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un botón"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
  • 13. android:text="Un texto cualquiera"/> </TableRow> </TableLayout> RelativeLayout permite comenzar a situar los elementos en cualquiera de los cuatro lados del contenedor e ir añadiendo nuevos elementos pegados a estos. <RelativeLayout xmlns:android="http://schemas... android:layout_height="match_parent" android:layout_width="match_parent"> <AnalogClock android:id="@+id/AnalogClock01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true"/> <CheckBox android:id="@+id/CheckBox01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/AnalogClock01" android:text="Un checkBox"/> <Button android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un botón" android:layout_below="@+id/CheckBox01"/> <TextView android:id="@+id/TextView01"
  • 14. android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="Un texto cualquiera"/> </RelativeLayout> AbsoluteLayout permite indicar las coordenadas (x,y) donde queremos que se visualice cada elemento. No es recomendable utilizar este tipo de Layout. La aplicación que estamos diseñando tiene que visualizarse correctamente en dispositivos con cualquier tamaño de pantalla. Para conseguir esto, no es una buena idea trabajar con coordenadas absolutas. De hecho, este tipo de Layout ha sido marcado como obsoleto. <AbsoluteLayout xmlns:android="http://schemas. android:layout_height="match_parent" android:layout_width="match_parent"> <AnalogClock android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_x="50px" android:layout_y="50px"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un checkBox" android:layout_x="150px" android:layout_y="50px"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
  • 15. android:text="Un botón" android:layout_x="50px" android:layout_y="250px"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un texto cualquiera" android:layout_x="150px" android:layout_y="200px"/> </AbsoluteLayout> FrameLayout posiciona las vistas usando todo el contenedor, sin distribuirlas espacialmente. Este Layout suele utilizarse cuando queremos que varias vistas ocupen un mismo lugar. Podemos hacer que solo una sea visible, o superponerlas.Para modificar la visibilidad de un elemento utilizaremos la propiedad visibility. <FrameLayout xmlns:android="http://schemas... android:layout_height="mach_parent" android:layout_width="match_parent"> <AnalogClock android:layout_width="wrap_content" android:layout_height="wrap_content"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un checkBox"/> <Button android:layout_width="wrap_content"
  • 16. android:layout_height="wrap_content" android:text="Un botón" android:visibility="invisible"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Un texto cualquiera" android:visibility="invisible"/> </FrameLayout> video[Tutorial] Los Layouts en Android Recursos adicionales: Propiedades de RelativeLayout La lista de propiedades específicas de RelativeLayout es muy grande. Te recomendamos que la consultes en el Anexo B. Práctica: Uso de Layouts 1. Utiliza un RelativeLayout para realizar un diseño similar al siguiente: 2. Utiliza un TableLayout para realizar un diseño similar al siguiente: 3. Utiliza un AbsoluteLayout para realizar un diseño similar al siguiente. Ojo AbsoluteLayout lo encontrarás en la paleta Advanced no en la de Layouts. Trata de reutilizar el Layout creado en el punto anterior.
  • 17. 4. Visualiza el resultado obtenido en el punto anterior en diferentes tamaños de pantalla. ¿Ha sido una buena idea usar AbsoluteLayout? ¿Se te ocurre otra forma de realizar este diseño de forma que se visualice correctamente en cualquier tipo de pantalla? 5. Trata de hacer el ejercicio anterior utilizando LinearLayout. 6. Visualiza el resultado obtenido en diferentes tamaños de pantalla. ¿Has resuelto el problema? Preguntas de repaso y reflexión: Los Layouts Pincha aquí para hacer un test. También podemos utilizar otras clases de Layouts, que son descritas a continuación: ScrollView: Visualiza una columna de elementos; cuando estos no caben en pantalla se permite un deslizamiento vertical. HorizontalScrollView: Visualiza una fila de elementos; cuando estos no caben en pantalla se permite un deslizamiento horizontal. TabHost: Proporciona una lista de ventanas seleccionables por medio de etiquetas que pueden ser pulsadas por el usuario para seleccionar la ventana que desea visualizar. Se estudia al final del capítulo. ListView: Visualiza una lista deslizable verticalmente de varios elementos. Su utilización es algo compleja. Se verá un ejemplo en el capítulo siguiente.
  • 18. GridView: Visualiza una cuadrícula deslizable de varias filas y varias columnas. ViewFlipper: Permite visualizar una lista de elementos de forma que se visualice uno cada vez. Puede ser utilizado para intercambiar los elementos cada cierto intervalo de tiempo. Una aplicación de ejemplo: Mis Lugares A lo largo de este curso vamos a ir creando una aplicación de ejemplo que toque los aspectos más significativos de Android. Comenzamos en este capítulo creando una serie de vistas que nos permitirán diseñar un sencillo interfaz de usuario. Práctica: Creación de la aplicación Mis Lugares. 1. Crea un nuevo proyecto con los siguientes datos: Application Name: Mis Lugares Project Name: MisLugares Package Name: org.example.mislugares Minimun Required SDK: API 8: Android 2.2 (Froyo) Target SDK: API 18 Compile With: API 19: Android 4.4 Activity Name: MainActivity Layout Name: activity_main NOTA: Los dos últimos parámetros se introducen en la última ventana. 2. Abre el fichero res/layout/activity_main.xml y trata de crear una vista similar a la que ves a continuación. Ha de estar formada por un LinearLayout que contiene un TextView y cuatro Button. Trata de utilizar recursos para introducir los cinco textos que aparecen.
  • 19. Solución: 1. El fichero activity_main.xml ha de ser similar al siguiente: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:padding="30dp" tools:context=".MainActivity" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/app_name" android:gravity="center" android:textSize="25sp " android:layout_marginBottom="20dp"/> <Button android:id="@+id/Button01" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/accion_mostrar"/> <Button android:id="@+id/Button02" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/accion_preferencias"/> <Button android:id="@+id/Button03" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/accion_acerca_de"/> <Button android:id="@+id/Button04" android:layout_height="wrap_content" android:layout_width="match_parent"
  • 20. android:text="@string/accion_salir"/> </LinearLayout> 2. El fichero res/values/strings.xml ha de tener el siguiente contenido: <resources> <string name="accion_mostrar">Mostrar Lugares</string> <string name="accion_preferencias">Preferencias</string> <string name="accion_acerca_de">Acerca de </string> <string name="accion_salir">Salir</string> <string name="app_name">Mis Lugares</string> <string name="action_settings">Settings </string> </resources> Práctica: Un formulario para introducir nuevos lugares El objetivo de esta práctica es crear un layout que permita introducir y editar lugares en la aplicaciónMis Lugares. 1. Crea un nuevo layout con nombre edicion_lugar.xml. 2. Ha de parecerse al siguiente formulario. Puedes basarte en un LinearLayout o un RelativeLayoutpara distribuir los elementos. Pero es importante que este layout, se encuentre dentro de un ScrollViewpara que cuando el formulario no quepa en pantalla se pueda desplazar verticalmente. 3. Introduce a la derecha del TextView con texto “Tipo:” un Spinner con id tipo. Más adelante configuraremos esta vista para que muestre un desplegable con los tipos de lugares. 4. Las vistas EditText han de definir el atributo id con los valores: nombre, direccion, telefono, url y comentario. Utiliza también el atributo hint para dar indicaciones sobre el valor a introducir. Utiliza el atributo inputType para indicar qué tipo de entrada esperemos. De esta manera se mostrará un teclado adecuado (por ejemplo si introducimos un correo electrónico aparecerá la tecla @). Nota: El atributo inputType admite los siguientes valores (en negrita los que has de gastar en este ejercicio): none, text, textCapCharacters, textCapWords, textCapSentences, textAutoCorrect, textAutoComplete, textMultiLine, textImeMultiLine, textNoSuggestions, textUri, textEmailAddress, textEmailSubject. textShortMessage, textLongMessage, textPersonName, textPostalAddress, textPassword, textVisiblePassword, textWebEditText, textFilter, textPhonetic, textWebEmailAddress, textWebPassword, number, numberSigned, numberDecimal, numberPassword, phone, datetime, date y time. 5. Abre la clase MainActivity y reemplaza: setContentView(R.layout.activity_main); por setContentView(R.layout.edicion_lugar);
  • 21. 6. Ejecuta la aplicación y verifica como cambia el tipo de teclado en cada EditText. Solución: <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/t_nombre" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Nombre:" android:textAppearance="?android:attr/textAppearanceMedium" /> <EditText android:id="@+id/nombre" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/t_nombre" android:hint="algo que identifique el lugar" > <requestFocus/> </EditText <TextView android:id="@+id/t_tipo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/nombre" android:text="Tipo:" android:textAppearance="?android:attr/textAppearanceMedium" /> <Spinner android:id="@+id/tipo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/t_tipo" android:layout_toRightOf="@id/t_tipo" /> <TextView android:id="@+id/t_direccion" android:layout_width="wrap_content"
  • 22. android:layout_height="wrap_content" android:layout_below="@id/t_tipo" android:text="Dirección:" android:textAppearance="?android:attr/textAppearanceM edium" /> <EditText android:id="@+id/direccion" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/t_direccion" android:hint="dirección del lugar" android:inputType="textPostalAddress" /> <TextView android:id="@+id/t_telefono" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/direccion" android:text="Telefono:" android:textAppearance="?android:attr/textAppearanceMedium" /> <EditText android:id="@+id/telefono" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/t_telefono" android:layout_alignTop="@id/t_telefono" android:hint="teléfono para contactar" android:inputType="phone" /> <TextView android:id="@+id/t_url" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/telefono" android:text="Url:" android:textAppearance="?android:attr/textAppearanceM edium" /> <EditText android:id="@+id/url" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/t_url" android:hint="página web"
  • 23. android:inputType="textUri" /> <TextView android:id="@+id/t_comentario" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/url" android:text="Comentario:" android:textAppearance="?android:attr/textAppearanceM edium" /> <EditText android:id="@+id/comentario" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/t_comentario" android:hint="introduce tus notas" android:inputType="textMultiLine" /> </RelativeLayout> </ScrollView> Una aplicación de ejemplo: Asteroides A lo largo de este libro vamos a ir creando una aplicación de ejemplo que toque los aspectos más significativos de Android. Comenzamos en este capítulo creando una serie de vistas que nos permitirán diseñar un sencillo interfaz de usuario. Si quieres ver cómo quedará la aplicación una vez termines el libro puedes ver el siguiente vídeo: video[Tutorial] Asteroides Enlaces de interés: Asteroides: Puedes descargarte la aplicación de Google Play (https://play.google.com/store/apps/details?id=es.upv.asteroides&hl) Práctica: Creación de la aplicación Asteroides. 1. Crea un nuevo proyecto con los siguientes datos: Application Name: Asteroides Project Name: Asteroides Package Name: org.example.asteroides Minimun Requiered SDK: API 8: Android 2.2 (Froyo) Target SDK: API 17: Android 4.2 Compile With: API 17: Android 4.2 Activity Name: Asteroides Layout Name: main
  • 24. NOTA: Los dos últimos parámetros se introducen en la última ventana. 2. Abre el fichero res/Layout/main.xml y trata de crear una vista similar a la que ves a continuación. Ha de estar formada por un LinearLayout que contiene un TexView y cuatro Button. Trata de utilizar recursos para introducir los cinco textos que aparecen. Solución: 1. El fichero main.xml ha de ser similar al siguiente: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent"
  • 25. android:layout_height="match_parent" android:gravity="center" android:padding="30dip" tools:context=".Asteroides" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/tituloAplicacion" android:gravity="center" android:textSize="25sp " android:layout_marginBottom="20dip"/> <Button android:id="@+id/Button01" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/Arrancar"/> <Button android:id="@+id/Button02" android:layout_height="wrap_content" android:layout_width="march_parent" android:text="@string/Configurar"/> <Button android:id="@+id/Button03" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/Acercade"/> <Button android:id="@+id/Button04" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/Salir"/> </LinearLayout> 2. El fichero res/values/strings.xml ha de tener el siguiente contenido: <resources> <string name="Arrancar">Jugar</string> <string name="Configurar">Configurar</string> <string name="Acercade">Acerca de </string> <string name="Salir">Salir</string> <string name="tituloAplicacion">Asteroides</string> <string name="hello">Hello World, Asteroides! </string> <string name="app_name">Asteroides</string> </resources>
  • 26. Recursos alternativos Una aplicación Android va a poder ser ejecutada en una gran variedad de dispositivos. El tamaño de pantalla, la resolución o el tipo de entradas puede variar mucho de un dispositivo a otro. Por otra parte, nuestra aplicación ha de estar preparada para diferentes modos de funcionamiento, como el modo automóvil o el modo noche, y para poder ejecutarse en diferentes idiomas. A la hora de crear el interfaz de usuario hemos de tener en cuenta todas estas circunstancias. Afortunadamente la plataforma Android nos proporciona una herramienta de gran potencia para resolver este problema, el uso de los recursos alternativos. Práctica: Recursos alternativos en Mis Lugares 1. Ejecuta la aplicación creada en el punto anterior en el emulador. 2. Los teléfonos móviles basados en Android permiten cambiar la configuración en apaisado y en vertical. Para conseguir este efecto con el emulador pulsa Ctrl+F11. Si, usando un dispositivo pequeño observas el resultado de la vista que acabas de diseñar en vertical no queda todo lo bien que desearíamos. Para resolver este problema Android te permite diseñar una vista diferente para la configuración horizontal y otra para vertical. 3. Crea la carpeta res/layout-land. Para ello puedes pulsa con el botón derecho sobre la carpeta res y seleccona New > Folder. 4. Copia en ella el fichero activity_main.xml.Para ello selecciona el fichero y pulsa Ctrl-C. Selecciona la carpeta destino y pulsa Ctrl-V. 5. Crea una vista similar a la que ves a continuación: formada por un LinearLayout que contiene un TextView y un TableLayout con dos Button por columna. 6. Ejecuta de nuevo la aplicación y observa como la vista se ve correctamente en las dos orientaciones. Solución: Has de obtener un código XML similar al siguiente:
  • 27. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:padding="30dp" tools:context=".MainActivity" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/app_name" android:gravity="center" android:textSize="25sp" android:layout_marginBottom="20dp"/> <TableLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:stretchColumns="*"> <TableRow> <Button android:id="@+id/Button01" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/accion_mostrar"/> <Button android:id="@+id/Button02" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/accion_preferencias"/> </TableRow> <TableRow> <Button android:id="@+id/Button03" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/accion_acerca_de"/> <Button android:id="@+id/Button04" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="@string/accion_salir"/> </TableRow>
  • 28. </TableLayout> </LinearLayout> NOTA: Para conseguir en un TableLayout, que las columnas se ajusten a todo el ancho de la tabla poner stretchColumns="*". stretchColumns="0"significa que asigne el ancho sobrante a la primera columna.stretchColumns="1"significa que asigne el ancho sobrante a la segunda columna. stretchColumns="*"significa que asigne el ancho sobrante entre todas las columnas. Android utiliza una lista de sufijos para expresar recursos alternativos. Estos sufijos pueden hacer referencia a la orientación del dispositivo, al lenguaje, la región, la densidad de píxeles, la resolución, el método de entrada,… Por ejemplo, si queremos traducir nuestra aplicación al inglés, español y francés. Siendo el primer idioma el usado por defecto, crearíamos tres versiones del fichero strings.xml y lo guardaríamos en los siguientes tres directorios: res/values/strings.xml res/values-es/strings.xml res/values-fr/strings.xml Ejercicio paso a paso: Traducción de Mis Lugares 1. Crea la carpeta res/values-en. 2. Copia en ella el fichero strings.xml. 3. Traduce en este fichero todas las cadenas al inglés. 4. Ejecuta la aplicación. 5. Vamos a cambiar la configuración de idioma den un dispositivo Android. Para ello, accede a Ajustes del dispositivo (Settings) y selecciona la opción Mi dispositivo > Idioma e introducción. Dentro de esta opción selecciona como idioma Español. NOTA:Observa que en otros idiomas permite seleccionar tanto el idioma como la región.Por desgracia, para el español solo permite dos regiones España y Estados Unidos. 6. Observa cómo, ahora se ha traducido el texto. 7. ¿Qué pasaría si nuestra aplicación se ejecuta en un terminal configurado en chino? ¿Aparecerán las cadenas en castellano o en inglés? ¿Piensas que esta es una buena decisión de diseño? ¿Cómo lo podrías solucionar? Respuestas: Aparecería en castellano. Mala decisión, mejor si aparece en inglés, que es un idioma conocido universalmente. Habría que poner el fichero strings.xml con los textos en ingles en la caspeta de recurso por defecto (res/values) y el fichero con los textos en castellano en la carpeta res/values-es. 8. Realiza los cambios propuestos en el punto anterior. Otro ejemplo de utilización de recursos diferenciados lo podemos ver con el icono que se utiliza para lanzar la aplicación. Observa como, al crear una aplicación, este icono se crea en cinco carpetas drawable diferentes, para utilizar un icono distinto según la densidad de píxeles del dispositivo: res/drawable-ldpi/ic_launcher.png res/drawable-mdpi/ic_launcher.png
  • 29. res/drawable-hdpi/ic_launcher.png res/drawable-xhdpi/ic_launcher.png res/drawable-xxhdpi/ic_launcher.png NOTA:En el siguiente capítulo se describe porque se actua de esta manera.. Resulta posible indicar varios sufijos concatenados; por ejemplo: res/values-en-rUS/strings.xml res/values-en-rUK/strings.xml Pero cuidado, Android establece un orden a la hora de encadenar sufijos. Puedes encontrar una lista de estos sufijos en el apendice C y en este enlace: http://developer.android.com/guide/topics/resources/providing-resources.html Para ver los sufijos disponibles también puedes pulsar con el botón derecho sobre una carpeta de recursos y seleccionar New > Other… > Android > Android XML File. Esta opción te permite crear un nuevo fichero XML y poner el sufijo deseado de forma y orden correcto. video[Tutorial] Uso de recursos alternativos en Android Práctica: Creando un Layout para tabletas en Mis Lugares Si ejecutas la aplicación Asteroides en una tableta observarás que los botones son demasiado alargados: 1. Trata de hacer un Layout alternativo a main.xml, que sea utilizado en pantallas de tamaño xlarge (7-10,5 pulgadas) en orientación land (apaisado). Simplemente poniendo un margen mayor en el Layout se conseguirá unos botones más proporcionados.
  • 30. 2. Si lo deseas también puedes personalizar el fondo de la pantalla (atributo background), los tamaños de letras, colores, etc. 3. Verifica que la aplicación se visualiza correctamente en todos los tipos de pantalla, tanto en horizontal como en vertical. Solución: 1. Crea la carpeta layout-xlarge-land y copia en ella el fichero activity_main.xml. 2. En el nuevo fichero modifica el valor que se usa como margen interno: <LinearLayout … android:padding="150dp"… > En la siguiente sección trataremos de resolver de una forma más adecuada la asignación de este margen. 3. Ejecuta en un emulador o tableta real de 10 pulgadas y verifica que el resultado: Tipos de recursos La definición de los recursos en Android es un aspecto muy importante en el diseño de una aplicación. Una de sus principales ventajas es que facilita a los diseñadores gráficos e introductores de contenido trabajar en paralelo con los programadores. Añadir un recurso a nuestra aplicación es muy sencillo, no tenemos más que añadir un fichero dentro de una carpeta determinada de nuestro proyecto. Para cada uno de los recursos que añadamos el sistema crea, de forma automática, un id de recurso dentro de la clase R. Tipos de recursos Según la carpeta que utilicemos el recurso creado será de un tipo específico. Pasamos a enumerar las carpetas y tipos posibles: carpeta identificador Descripción res/drawable/ R.drawable Ficheros en bitmap (.png, .jpg o .gif). Ficheros PNG en formato Nine-patch (.9.png). Ficheros XML con descriptores gráficos (ver clase Drawable) res/layout/ R.layout Ficheros XML con los Layouts usados en la aplicación.
  • 31. res/menu/ R.menu Ficheros XML con la definición de menús. Podemos asignar una actividad o una vista. res/anim/ R.anim Fichero XML que permiten definir una animaciones Tween también conocidas como animaciones de vista. res/animator R.animator Ficheros XML que permiten modificar las propiedades de un objeto a lo largo del tiempo Ver sección: animación de propiedades. Solo desde la versión 3.0. res/xml/ R.xml Otros ficheros XML, como los ficheros de preferencias res/raw/ R.raw Ficheros que se encuentran en formato binario. Por ejemplo ficheros de audio o vídeo. res/values/ Ficheros XML que definen un determinado valor para definir un color, estilo, cadena de caracteres… se describen en la siguiente tabla. Veamos los tipos de recursos que encontramos dentro de la carpeta values: fichero por defecto identificador Descripción strings.xml R.string Identifica cadenas de caracteres <string name="saludo">¡Hola Mundo!</string> colors.xml R.color Un color definido en formato ARGB (alfa, rojo, verde y azul). Los valores se indica hexadecimal en uno de los siguientes formatos: #RGB, #ARGB, #RRGGBB ó #A <color name="verde_opaco">#0f0</color> <color name="red_translucido">#80ff0000</color> dimensions.xml R.dimen Un número seguido de una unidad de medida. px - pixeles, mm - milímetros, in – pulgadas, pt – puntos (=1/72 pulgadas), dp – p independientes de la densidad (=1/160 pulgadas), sp – igual que dp pero cambia preferencias de tamaño de fuente. <dimen name="alto">2.2mm</dimen> <dimen name="tamano_fuente">16sp</dimen> styles.xml R.style Definen una serie de atributos que pueden ser aplicados a una vista o a una activ aplican a una actividad se conocen como temas. <style name="TextoGrande"parent="@style/Text"> <item name="android:textSize">20pt</item> <item name="android:textColor">#000080</item> </style> R.int Define un valor entero. <integer name="max_asteroides">5</integer> R.bool Define un valor booleano. <bool name="misiles_ilimitados">true</bool> R.id Define un recurso de ID único. La forma habitual de asignar ID a los recursos es atributo id="@+id/nombre". Aunque en algunos casos puede ser interesante dis previamente creados, para que los elementos así nombrados tengan una determ Este tipo de IDs se utilizan en las vistas TabHost y ListView.
  • 32. <item type="id" name="button_ok"/> <item type="id" name="dialog_exit"/> R.array Una serie ordenada de elementos. Pueden ser de strings, de enteros o de recurs (TypedArray) <string-array name="dias_semana"> < <item>lunes</item> <item>martes</item> </string-array> <integer-array name="primos"> <item>2</item><item>3</item><item>5</item> </integer-array> <array name="asteroides"> <item>@drawable/asteroide1</item> <item>@drawabl </array> Aunque el sistema crea ficheros que aparecen en la columna de la izquierda de la tabla anterior y se recomienda definir los recursos de cadena dentro de strings.xml, hay que resaltar que no es más que una sugerencia de organización. Sería posible mezclar cualquier tipo de recurso de esta tabla dentro de un mismo fichero y poner a este fichero cualquier nombre. video[Tutorial] Tipos de recursos en Android Acceso a los recursos Una vez definido un recurso este puede ser utilizado desde un fichero XML o desde Java. A continuación se muestra un ejemplo desde XML: <ImageView android:layout_height="@dimen/alto" android:layout_width="match_parent" android:background="@drawable/asteroide" android:text="@string/saludo" android:text_color="@color/verde_opaco"/> Para acceder a un recurso definido en los ejemplos anteriores desde Java usaremos el siguiente código: Resources res =getResources(); Drawable drawable =res.getDrawable(R.drawable.asteroide); String saludo = res.getString(R.string.saludo); int color =res.getColor(R.color.verde_opaco); float tamanoFuente =res.getDimension(R.dimen.tamano_fuente); int maxAsteroides =res.getInteger(R.integer.max_asteroides); boolean ilimitados = res.getBoolean(R.bool.misiles_ilimitados); String[] diasSemana =res.getStringArray(R.array.dias_semana); int[] primos =res.getIntArray(R.array.primos); TypedArray asteroides =res.obtainTypedArray(R.array.asteroides); Drawable asteroide1 =asteroides.getDrawable(0);
  • 33. Ejercicio paso a paso: Creando un Layout alternativo con el sufijo -sw 1. Utilizando el editor visual de vistas previsualiza el Layout activity_main.xml modificado en la práctica anterior. 2. Utiliza el segundo botón de la barra superior para seleccionar una tableta de 10 pulgadas: 3. Ha de utilizarse el Layout alternativo creado en la práctica. 4. Selecciona ahora una tableta de 7 pulgadas. Observa como ya no se utilizará este Layout. La razón es que este una tableta de 7 pulgadas se considera de tamaño large y no xlarge. Si quisiéramos aplicar también este Layout para este tamaño, tendríamos que crear una nueva carpeta con sufijo - large y copiar el Layout dentro. Copiar el mismo recurso dos veces no parece muy razonable. 5. Para ajustar nuestros diseños a los tamaños de pantalla en el Nivel de API 13 se introduce una alternativa más práctica: el sufijo -sw o ancho menor: Veamos cómo se utiliza. Primero se obtiene el menor entre ancho y alto de pantalla disponible y se compara el valor indicado en la carpeta. Solo se cargará el recurso si el valor obtenido es mayor al indicado en la carpeta. Si varias carpetas cumplen la condición se usa la carpeta con mayor valor. Es obligatorio utilizar dp como unidad (1dp=1/160 pulgadas). Este valor no se calcula con el ancho total de la pantalla física, si no con el espacio disponible para la aplicación. Los elementos permanentes del IU del sistema (como botones en pantalla) no se cuentan como espacio disponible. El uso habitual es para indicar en ancho mínimo que soporta un layout. Hay que recordar que se compara con el mínimo entre ancho y alto, por lo tanto, no afecta cambiar la inclinación de horizontal a vertical. Los valores típicos que se utilizan se muestran a continuación: sw320dp = 2’ = 50mm (móvil pequeño) sw480dp = 3’ = 76mm (móvil grande) sw600dp = 3,75’= 95mm (tableta 7’) sw720dp = 4,5’ = 114mm (tableta 10’) 6. Crea la carpeta layout-sw600dp-land y copia en ella el fichero activity_main.xml de la carpetalayout-xlarge-land. 7. Elimina la carpeta layout-xlarge-land. 8. Verifica que este Layout es utilizado tanto en carpetas de 7 y 10 pulgadas. Nota: El sufijo –sw aparece en el nivel de API 13 (v3.2). Esto significa que cuando esta aplicación sea cargada en un dispositivo con una versión anterior a la 3.2 la carpeta que acabamos de crear será ignorada. Esta circunstancia podrá darse dado que, el nivel mínimo de API seleccionado en Mis Lugares es 8 (v2.2). Ejercicio paso a paso: Uso de dimensiones en recursos alternativos Crear un nuevo recurso de Layout simplemente para cambiar los márgenes no es una buena idea. Si más adelante decidimos modificarlo, por ejemplo añadiendo un gráfico, tendremos que modificar cada uno de los Layouts creados. Cuando lo que quieras ajustar sea un tamaño (margen, tamaño de letra, ancho, alto, etc.), lo más recomendable es definir un recurso de dimensión y definirlo según el tamaño disponible. Este ejercicio ilustra cómo hacerlo.
  • 34. 1. En el explorador de paquetes busca el proyecto HolaMundo. Expande la capeta res. Observa como al crear un nuevo proyecto se ha creado el fichero dimens.xml en tres carpetas diferentes: 2. Abre el fichero dimens.xml en su versión por defecto (res/values/dimens.xml). Se mostrará: <resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> </resources> 3. Abre el fichero res/values-sw600dp/dimens.xml. Observa como no se incluye ninguna dimensión. Se ha creado para facilitarte la adaptación de los diseños de layout en pantallas de 7 pulgadas o más. 4. Abre el fichero res/values-sw720dp-land/dimens.xml. Se mostrará: <resources> <!-- Customize dimensions originally defined in res/values/dimens.xml (such as screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.--> <dimen name="activity_horizontal_margin">128dp</dimen> </resources> 5. Tras analizar estos tres ficheros, puedes decir que posibles valores tomarán las dos dimensiones definidas y cuando. Solición: activity_vertical_margin siempre valdrá 16dp y activity_horizontal_margin valdrá 128dp cuando estemos en una pantalla de más de 10 pulgadas en posición horizontal y en el resto de los casos 16dp. 6. Abre el fichero res/layout/activity_main.xml. Se mostrará: <RelativeLayout … android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" … > Obserba como se están utilizando las dimensiones definidas para indicar los márgenes inferior, izquierdo, derecho y superior. 7. Vamos a aplicar esta filosofía de trabajo a la aplicación Mis Lugares. 8. Abre el fichero MisLugares/res/layout/activity_main.xml. Reemplaza: <LinearLayout … android:padding="30dp" … > Por:
  • 35. <RelativeLayout … android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" … > 9. Reemplaza: <TextView … android:textSize="25sp"/> por: <TextView … android:textSize="@dimen/titulo" /> 10. Añade a cada uno de los cuatro botones el atributo textSize de la siguiente manera: <Button … android:textSize="@dimen/boton"/> 11. Realiza los cambios de los tres últimos puntos, pero ahora en el fichero res/layout- land/activity_main.xml. 12. Edita el fichero res/dimens.xml para obtener: <resources> <dimen name="activity_horizontal_margin">25dp</dimen> <dimen name="activity_vertical_margin">25dp</dimen> <dimen name="titulo">25sp</dimen> <dimen name="boton">16sp</dimen> </resources> 13. Edita el fichero res/values-sw600dp/dimens.xml para obtener: <resources> <dimen name="activity_horizontal_margin">75dp</dimen> <dimen name="titulo">35sp</dimen> <dimen name="boton">22sp</dimen> </resources> 14. Edita el fichero res/values-sw720dp-land/dimens.xml para obtener: <resources> <dimen name="activity_horizontal_margin">150dp</dimen> <dimen name="titulo">45sp</dimen> <dimen name="boton">30sp</dimen> </resources>
  • 36. 15. Tras la definiciones introducida ¿Qué valor tomará activity_horizontal_margin, cuando se ejecute la aplicación en una tableta de 110 pulgadas. Solución: Depende de su posición: en horizontal 150dp y en vertical 75 dp. 16. Borra la carpeta res/layout-sw600dp-land con su contenido. Ya no necesitamos esta layout. 17. Para verificar los resultados no es necesario disponer de tabletas de diferentes tamaños, ni siquiera crear diferentes emuladores. Puedes abrir la edición visual del layout activity_main y previsualizar en diferentes tamaños de pantalla y orientación. Es recomendable para esta prueba que tengas seleccionado en ajuste de zum, para que se ajuste al tamaño real: Recursos del sistema Además de los recursos que podamos añadir a nuestra aplicación, también podemos utilizar una serie de recursos que han sido incluidos en el sistema. video[Tutorial] Recursos del sistema en Android Usar recursos del sistema tiene muchas ventajas. No consumen memoria en nuestra aplicación, al estar ya incorporados al sistema. Además los usuarios están familiarizados con ellos. Por ejemplo, si utilizamos el recursoandroid.R.drawable.ic_menu_edit se mostrará al usuario el icono: . Muy posiblemente el usuario ya está familiarizado con este icono y lo asocie a la acción de editar. Otra ventaja es que los recursos del sistema se adaptan a las diferentes versiones de Android. Si se utiliza el tema android.R.style.Theme_Panel este es bastante diferente en cada una de las versiones, pero seguro que estará en consonancia con el resto de estilos para esta versión. Lo mismo ocurre con el icono anterior. Este icono es diferente en algunas versiones, pero al usar un recurso del sistema nos aseguramos que se mostrará el adecuado a la versión del usuario. Finalmente, estos recursos se adaptan siempre a las configuraciones locales. Si yo utilizo el recursoandroid.R.string.cancel este será “Cancelar”, “Cancel”, “取消”,... según el idioma escogido por el usuario. Obtener una lista con los recursos del sistema disponible no es sencillo. Te recomendamos que instales la aplicación Android.R en cualquier dispositivo para explorar los recursos del sistema.
  • 37. Para acceder a los recursos del sistema desde código usaremos la clase android.R. Se utiliza la misma estructura de jerárquica de clases. Por ejemplo android.R.drawable.ic_menu_edit. Para acceder desde XML utiliza la sintaxis habitual pero comenzando con @android:. Por ejemplo @android:drawable/ic_menu_edit. Estilos y temas Si tienes experiencia con el diseño de páginas Web habrás advertido grandes similitudes entre HTML y el diseño de Layouts. En los dos casos se utiliza un lenguaje de marcado y se trata de crear diseños independientes del tamaño de la pantalla donde serán visualizados. En el diseño web resulta clave las hojas de estilo en cascada (CSS) que permiten crear un patrón de diseño y aplicarlo a varias páginas. Cuando diseñes los Layouts de tu aplicación vas a poder utilizar unas herramientas similares conocidas como estilos y temas. Te permitirán crear patrones de estilo que podrán ser utilizados en cualquier parte de la aplicación. Estas herramientas te ahorrarán mucho trabajo y te permitirán conseguir un diseño homogéneo en toda tu aplicación. video[Tutorial] Estilos y Temas en Android Los estilos Un estilo es una colección de propiedades que definen el formato y apariencia que tendrá una vista. Podemos especificar cosas como tamaño, márgenes, color, fuentes, etc. Un estilo se define en ficheros XML, diferente al fichero XML Layout que lo utiliza. Veamos un ejemplo. El siguiente código:
  • 38. <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#00FF00" android:typeface="monospace" android:text="Un texto" /> Es equivalente a escribir: <TextView style="@style/MiEstilo" android:text="Un texto" /> Habiendo creado en el fichero res/values/styles.xml conel siguiente código: <?xml version="1.0" encoding="utf-8"?> <resources> <stylename="MiEstilo" parent="@android:style/TextAppearance.Medium"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:textColor">#00FF00</item> <item name="android:typeface">monospace</item> </style> </resources> Observa como un estilo puede heredar todas las propiedades de un padre (parámetro parent) y a partir de estas propiedades realizar modificaciones. Heredar de un estilo propio Si vas a heredar de un estilo definido por ti no es necesario utilizar el atributo parent. Por el contrario, puedes utilizar el mismo nombre de un estilo ya creado y completar el nombre con un punto más un sufijo.Por ejemplo: <stylename="MiEstilo.grande"> <item name="android:textSize">18pt</item> </style> Crearía un nuevo estilo que sería igual a MiEstilo más la nueva propiedad indicada. A su vez puedes definir otro estilo a partir de este: <stylename="MiEstilo.grande.negrita"> <item name="android:textStyle">bold</item> </style> Práctica: Creando un estilo 1. Abre el proyecto Asteroides o Mis Lugares (dependiendo del curso). 2. Crea un nuevo estilo con nombre EstiloTexto. 3. Aplícalo al título que aparece en el Layout activity_ main.xml
  • 39. 4. Crea un nuevo estilo con nombre EstiloTexto.Botones. Este ha de modificar alguno de los atributos anteriores y añadir otros, como padding. 5. Aplícalo a todos los botones del Layout. 6. Visualiza el resultado. Los temas Un tema es un estilo aplicado a toda una actividad o aplicación, en lugar de a una vista individual. Cada elemento del estilo solo se aplicará a aquellos elementos donde sea posible. Por ejemplo, CodeFont solo afectará al texto. Para aplicar un tema a toda una aplicación edita el fichero AndroidManifest.xml y añade el parámetroandroid:theme en la etiqueta application: <application android:theme="@style/MiTema"> También puedes aplicar un tema a una actividad en concreto: <activity android:theme="@style/MiTema"> Además de crear tus propios temas vas a poder utilizar algunos disponibles en el sistema. Puedes encontrar una lista de todos los estilos y temas disponibles en Android en:http://developer.android.com/reference/android/R.style.html Ejercicio paso a paso: Aplicando un tema del sistema 1. Abre el proyecto Asteroides o Mis Lugares (dependiendo del curso). 2. Aplica a la actividad principal el tema android:style/Theme.Dialog tal y como se acaba de mostrar. 3. Visualiza el resultado. Práctica: Creando un tema 1. Abre el proyecto Asteroides o Mis Lugares (dependiendo del curso). 2. Crea un tema con nombre TemaAsteroides que herede de android:style/Theme.NoTitleBar. Este tema no muestra la barra con el nombre de la aplicación. 3. Aplica este tema a la aplicación. Uso práctico de Vistas y Layouts
  • 40. En este apartado vamos a aprender a usar varios tipos de vistas y Layouts desde un punto de vista práctico. También empezaremos a escribir código que será ejecutado cuando ocurran ciertos eventos: Ejercicio paso a paso: Un botón con gráficos personalizados 1. Crea un nuevo proyecto con los siguientes datos: Application name: MasVistas Package name: org.example.masvistas Minimun Requiered SDK: API 7 Android 2.1 (Eclair) Activity Name: MasVistasActivity Layout Name: main.xml 2. Crea el fichero boton.xml en la carpeta res/drawable/. Para ello puedes utilizar el menúArchivo/Nuevo/Android XML File y pon en File: “botón” y selecciona en tipo Drawable. Reemplaza el código por el siguiente: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/boton_pulsado" android:state_pressed="true" /> <item android:drawable="@drawable/boton_con_foco" android:state_focused="true" /> <item android:drawable="@drawable/boton_normal" /> </selector> Este XML define un recurso único gráfico (drawable) que cambiará en función del estado del botón. El primer <item> define la imagen usada cuando se pulsa el botón, el segundo <item> define la imagen usada cuando el botón tiene el foco (cuando el botón está seleccionado con la rueda de desplazamiento o las teclas de dirección), el tercero la imagen en estado normal. Los gráficos y en concreto los drawables serán estudiados en el CAPÍTULO 1 y CAPÍTULO 4. NOTA: El orden de los elementos <item> es importante. Cuando se va a dibujar se recorren los ítems en orden hasta que se cumpla una condición. Debido a que "boton_normal" es el último, sólo se aplica cuando las condicionesstate_pressedy state_focused no se cumplen. 3. Descarga las tres imágenes que aparecen a continuación de www.androidcurso.com. El nombre que ha de tener cada fichero aparece debajo: boton_normal.jpg boton_con_foco.jpg boton_pulsado.jpg 4. Arrastra estas imágenes a la carpeta res/drawable/ del proyecto. 5. Abre el fichero res/layout/main.xml. 6. Elimina el TextView que encontrarás dentro del LinearLayout. 7. Selecciona el LinerLayout e introduce en el atributo Background el valor #FFFFFF.
  • 41. 8. Arrastra una vista de tipo Button dentro del LinearLayout. 9. Selecciona el atributo Background y pulsa en el botón selector de recurso (con puntos suspensivos). Selecciona Drawable/boton. 10. Modifica el atributo Text para que no tenga ningún valor. 11. Introduce en el atributo onClick el valor sePulsa. (Ojo; este atributo solo está disponible a partir de la versión 1.6) 12. Abre el fichero MasVistasActivity.java e introduce al final, antes de la última llave, el código: public void sePulsa(View view){ Toast.makeText(this, "Pulsado", Toast.LENGTH_SHORT).show(); } Pulsa Ctrl-Shift-O para que se añadan automáticamente los paquetes que faltan en la sección import. El método anterior será ejecutado cuando se pulse el botón. Este método se limita a lanzar un Toast, es decir, un aviso que permanece un cierto tiempo sobre la pantalla y luego desaparece. Los tres parámetros son: 1-El contexto utilizado, coincide con la actividad. 2-El texto a mostrar y 3-El tiempo que permanecerá este texto. Los conceptos de actividad y contexto serán desarrollados en el siguiente capítulo. 13. Ejecuta el proyecto y verifica el resultado. 14. El código resultante para el fichero main.xml se muestra a continuación: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFFFFF"> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/boton" android:onClick="sePulsa"/> </LinearLayout> Acceder y modificar las propiedades de las vistas por código Ejercicio paso a paso: Acceder y modificar las propiedades de las vistas por código 1. Abre el Layout main.xml creado en el ejercicio anterior. 2. En la paleta de vistas, dentro de Text Fields, busca Number (Decimal) y arrástralo encima del botón rojo. 3. Modifica algunos atributos de esta vista: Hint = “Introduce un número”, id = “@+id/entrada” 4. En la paleta de vistas, dentro de Form Widgets, busca Button y arrástralo encima del botón rojo. 5. Modifica algunos atributos de esta vista: Haz que su ancho ocupe toda la pantalla, que su texto sea “0”. 6. En la paleta de vistas, dentro de Form Widgets, busca Large Text y arrástralo debajo del botón rojo. 7. Modifica algunos atributos de esta vista: TextColor = #0000FF, Text = “”, Hint = “Resultado”, id= “@+id/salida”. 8. Abre el fichero MasVistaActivity.java. Vamos a añadir dos nuevas propiedades a la clase. Para ello copia el siguiente código al principio de la clase (antes del método onCreate): private EditText entrada; private TextView salida;
  • 42. 9. Copia al final del método onCreate las siguientes dos líneas: entrada = (EditText) findViewById(R.id.entrada); salida = (TextView) findViewById(R.id.salida); 10. Como se explicó al principio del capítulo, las diferentes vistas definidas en main.xml, son creadas como objetos Java cuando se ejecuta setContentView(R.layout.main). Si queremos manipular algunos de estos objetos hemos de declararlos (paso 8) y asignarles el objeto correspondiente. Para ello, hay que introducir el atributo id en xml y utilizar el métodofindViewById(R.id.valor_en_atributo_id). Este método devuelve un objeto de la claseView, no obstante los objetos declarados (entrada y salida) no son exactamente de esta clase por lo que Java no permite una asignación directa. En estos casos hemos de utilizar una conversión de tipo (type cast) para poder hacer la asignación. Para más información al respecto leer el apartadoPolimorfismo del tutorial de Java Esencial. 11. Introduce en el atributo onClick del botón con id boton0 el valor “sePulsa0”. 12. Añade el siguiente método al final de la clase MasVistasActivity. public void sePulsa0(View view){ entrada.setText(entrada.getText()+"0"); } 13. Añade al botón con texto “0” el atributo tag = “0”. 14. Modifica el método sePulsa0 de la siguiente forma: public void sePulsa0(View view){ entrada.setText(entrada.getText()+(String)view.getTag()); } El resultado obtenido es equivalente al anterior. En algunos casos será interesante utilizar un mismo método como escuchadorde eventos de varias vistas.Podrás averiguar la vista que causó el evento,dado que esta es pasada como parámetro del método. En el ejemplo sabemos que en el atributo tagguardamos el carácter a insertar. El atributo tag puede serusado libremente por el programador para almacenar un objeto de la clase Object (mas info ). En nuestro caso hemos almacenado un objetoString, por lo que necesitamos una conversión de tipo. Otro ejemplo de Polimorfismo. NOTA: Utiliza esta forma de trabajar en la práctica para no tener que crear un método onClick para cada botón de la calculadora. 15. Modifica el código de sePulsa con el siguiente código: public void sePulsa(View view){ salida.setText(String.valueOf( Float.parseFloat(entrada.getText().toString())*2.0)); } En este código el valor de entrada es convertido en Float, multiplicado por dos y convertido en String para ser asignado a salida. 16. Ejecuta el proyecto y verifica el resultado. Uso de TabHost La vista TabHost nos va a permitir crear un interfaz de usuario basado en pestañas. Este permite de una forma muy intuitiva ofrecer al usuario diferentes vistas, sin más que seleccionar una de las pestaañas que se muestran en la parte superior:
  • 43. Para crear una interfaz de usuario con pestañas, es necesario utilizar FragmentTabHost y TabWidget. ElFragmentTabHost debe ser el nodo raíz para el diseño, que contendrá tanto el TabWidget para la visualización de las pestañas, como un FrameLayout para mostrar el contenido. A continuación se muestra el esquema a utilizar: Nota: En las primeras versiones de Android se usaba TabHost en lugar FragmentTabHost. A partir del nivel de API 13, TabHost ha sido declarado como obsoleto. Google ha reorientado su gerarquia de clases para introducir el concepto de fragments. No obstante, puedes seguir utilizando TabHost sin ningún problema. Nota: Hasta la vesión 3.0 (API 11) no aparece FragmentTabHost. Entonces, no podría usarse en niveles de API anteriores. Para resolver este problema, y más generalmente para poder usar fragments en versiones anteriores a la 3.0, Google ha creado la librería de compatibilidad[1] (android.support).. Es añadida por defecto al crear un nuevo proyecto. Poe lo tanto, podemos usar Fragments y clases relacionadas desde versiones <android.support.v4.app.FragmentTabHost android:id="@android:id/tabhost" …/> <LinearLayout …> <TabWidget android:id="@android:id/tabs" …/> <FrameLayout android:id="@android:id/tabcontent" …> <PrimerLayout … /> <SegundoLayout … /> <TercerLayout … /> … </FrameLayout> </LinearLayout> </TabHost> [1]http://developer.android.com/tools/extras/support-library.html
  • 44. Puedes implementar el contenido de dos maneras: usando las pestañas para intercambiar puntos de vista dentro de la misma actividad, o puedes utilizar las pestañas para cambiar entre actividades totalmente independientes. En este apartado, vamos a crear una interfaz de usuario con pestañas que utiliza una única actividad. Para hacerlo con diferentes actividades para cada pestaña puedes seguir el tutorial: Nota: El siguiente vídeo utiliza TabHost en lugar FragmentTabHost. No obstante, los conceptos que se explican siguen siendo válidos. Puedes ver algunos aspectos relacionados en formato poli[Media] La vistaTabHost en Android Ejercicio paso a paso: Uso de TabHost 1. Crea un nuevo proyecto con los siguientes datos Application name: TabHost Package name: org.example.tabhost Minimun Requiered SDK: API 7 Android 2.1 (Eclair) Activity Name: TabHostActivity Layout Name: activity_main.xml 2. Reemplaza el código de activity_main.xml por el siguiente: <android.support.v4.app.FragmentTabHostxmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/tab1" android:orientation="vertical"
  • 45. android:layout_height="wrap_content" android:layout_width="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="esto es una pestaña" /> <EditText android:layout_height="wrap_content" android:layout_width="match_parent"/> </LinearLayout> <TextView android:id="@+id/tab2" android:layout_width="match_parent" android:layout_height="match_parent" android:text="esto es otra pestaña" /> <TextView android:id="@+id/tab3" android:layout_width="match_parent" android:layout_height="match_parent" android:text="esto es la tercera pestaña" /> </FrameLayout> </LinearLayout> </android.support.v4.app.FragmentTabHost> Como puedes observarse ha creado un FragmentTabHost debe ser el nodo raíz para el diseño, que contiene dos elementos combinados por medio de un LinearLayout. El primero es un TabWidget para la visualización de las pestañas y el segundo es un FrameLayout para mostrar el contenido de la ficha. Dentro de este FrameLayout hay tres elementos, cada uno de los cuales contendrá las vistas a mostrar para cada una de las lengüetas.Tienes que tener especial cuidado con los atributos id. El FragmentTabHost debe llamarse siempre "@android:id/tabhost", mientras que elTabWidget ha de llamarse "@android:id/tabs". De esta forma el sistema conocerá la finalidad de cada uno de estos elementos. Por otra parte, cada una de las vistas de contenido introducidas dentro del FrameLayout han de tener un id asignado por ti, como "@+id/tab1". 3. Para que un FragmentTabHost funcione resulta imprescindible introducir el siguiente código. Abre el ficheroMainActivity.java y reemplaza el código por el siguiente. public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TabHost tabHost = getTabHost(); tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator( "Título 1", null).setContent(R.id.tab1Layout)); tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator( "Título 2", null).setContent(R.id.tab2Layout)); tabHost.addTab(tabHost.newTabSpec("tab3").setIndicator( "Título 3", null).setContent(R.id.tab3Layout)); } } Observa como la clase creada extiende de TabActivity en lugar de Activity.Además, se han añadido varias líneas al final del método onCreate(). La primera línea obtiene la actividad que muestra las pestañas mediante getTabHost().Luego añadimos tantas pestañas como nos interese. Para cada una se crea indicando un tag (newTabSpec()), se le asocia un título y un icono (setIndicator()) y se indica donde
  • 46. está el contenido (setContent()). NOTA: Los iconos disponibles en el sistema y cómo crear nuevos icono será estudiado en el siguiente capítulo. 4. Ejecuta el proyecto y verifica el resultado. Uso de la etiqueta <include> en Layouts Un diseño basado en TabHost puede requerir ficheros xml muy extensos. Para organizar correctamente el trabajo y reutilizar diseños previos puede ser de gran ayuda la etiqueta <include> Ejercicio paso a paso: Uso de la etiqueta <include> en Layouts 1. Empezaremos realizando una copia del fichero MasVistas/res/layout/main.xml aTabLayout/res/layout/boton_rojo.xml. Para ello selecciona el primer fichero y pégalo en la carpeta MasVistas/res/layout. Te pedirá un nuevo nombre escribe boton_rojo.xml. Arrastra el nuevo fichero hasta la carpeta TabLayout/res/layout. 2. Realiza el mismo proceso con uno de los Layout creado en la práctica Uso de Layouts, donde se diseñaba el teclado de una calculadora. En nuestro proyecto ha de llamarse calculadora.xml 3. Realiza el mismo proceso con el Layout creado en el ejercicio paso a paso Creación visual de vistas. En nuestro proyecto ha de llamarse primer_layout.xml. 4.Añade el atributo android:id="@+id/tab1Layout" en el LineraLayout raíz de botón_rojo.xml. Añade el atributo android:id="@+id/tab2Layout" en calculadora.xml y "@+id/tab3Layout" en primer_la yout.xml. 5. Abre el fichero main.xml y reemplaza el FrameLayout por: <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/boton_rojo"/> <include layout="@layout/calculadora"/> <include layout="@layout/primer_layout"/> </FrameLayout> 6. Ejecuta el proyecto y verifica el resultado. Ojo: si pulsas alguno de los botones es posible que no funcione. Recuerda que no hemos copiado el código. Has podido comprobar cómo hemos conseguido un diseño muy complejo sin la necesidad de crear un xml demasiado grande. De esta forma, tenemos el código xml separado en cuatro ficheros diferentes. Además ha sido muy sencillo reutilizar diseños previos. Uso de FragmentTabHost A partir del nivel de API 13, TabHost ha sido declarado como obsoleto. Google ha reorientado su jerarquía de clases para introducir el concepto de fragment, de manera que en lugar de TabHost, propone utilizarFragmentTabHost. No obstante, podemos seguir utilizando TabHost sin ningún problema. La clase FragmentTabHost no aparece hasta la versión 3.0 (API 11). Entonces, no podría usarse en niveles de API anteriores. Para resolver este problema, y más generalmente para poder usar fragments en versiones anteriores a la 3.0, Google ha creado una librería de compatibilidad[1] (android.support). Es añadida por defecto al crear un nuevo proyecto. Gracias a esta librería, podemos usar fragments y clases relacionadas en todas las versiones.
  • 47. [1]http://developer.android.com/tools/extras/support-library.html Ejercicio paso a paso: Uso de FragmentTabHost 1. Crea un nuevo proyecto con los siguientes datos Application name: FragmentTabHost Package name: org.example.fragmenttabhost Minimun Requiered SDK: API 8 Android 2.2 (Froyo) 2. Reemplaza el código de activity_main.xml por el siguiente: <android.support.v4.app.FragmentTabHostxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mi_tabhost" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"/> <FrameLayout android:id="@+id/contenido" android:layout_width="match_parent" android:layout_height="0dp"/> </LinearLayout> </android.support.v4.app.FragmentTabHost> Como puedes observar se ha creado un FragmentTabHost, que contiene dos elementos combinados por medio de un LinearLayout. El primero es un TabWidget para la visualización de las pestañas y el segundo es un FrameLayout paramostrar el contenido asociado de cada lengüeta. En número de lengüetas y su contenido se indicará por código. Observa los valores con los atributos id. El TabWidget se ha utilizado "@android:id/tabs", un identificador fijo definido como recurso del sistema. De esta forma estamos indicando la finalidad que tiene. Para el resto de elementos se han definido nuevos identificadores 3. Abre el fichero MainActivity.java y reemplaza el código por el siguiente: package com.example.fragmenttabhost; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTabHost; public class MainActivity extends FragmentActivity { private FragmentTabHost tabHost;
  • 48. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tabHost = (FragmentTabHost) findViewById(R.id.mi_tabhost); tabHost.setup(this, getSupportFragmentManager(), R.id.contenido); tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("Lengüeta 1"), Tab1.class, null); tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("Lengüeta 2"), Tab2.class, null); tabHost.addTab(tabHost.newTabSpec("tab3").setIndicator("Lengüeta 3"), Tab3.class, null); } } Observa como la clase creada extiende de FragmentActivity en lugar de Activity. Esto permitirá que la actividad trabaje con Fragments, en concreto, vamos a crear un fragmnet para cada lengüeta. Se han añadido varias líneas en el método onCreate(). Empezamos inicializando la variable tabHost, luego se utiliza el método setup() para configurarla. Para ello indicamos el contexto, manejador de fragments y donde se mostrarán los fragments. Cada una de las siguientes tres líneas introduce una nueva lengüeta usando el método addTab().Se indican tres parámetros: Un objeto TabSpec, una clase con el Fragment a visualizar en la lengüeta y un Bundle por si queremos pasar información a la lengüeta. El método newTabSpec()crear una nueva lengüeta en un TabHost. Se le pasa como parámetro un String que se utiliza como identificador y devuelve el objeto de tipo TabSpec creado. Nota sobre Java: Dado que el método newTabSpec() devuelve un objeto de tipo TabSpec, tras la llamada podemos llamar al método setIndicator()que nos permitirá introducir un descriptos en la pestaña recién creada. NOTA:También podremos asignar iconos a las lengüetas con el método setIndicator(). Los iconos disponibles en el sistema y cómo crear nuevos icono será estudiado en el siguiente capítulo. 4.Crea un nuevo layout con nombre tab1.xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="match_parent"
  • 49. android:gravity="center vertical/center_horizontal" android:text="Lengüeta 1" android:textAppearance="?android:attr/textAppearanceMedium" /> </LinearLayout 5.Crea una nueva clase con Tab1.java: public class Tab1 extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.tab1, container, false); } } Nota sobre Java: Pulsa Ctrl-Shift-O, para que automáticamente se añadan los paquetes que faltan. Si la clase Fragment es encontrada en más de un paquete seleccionaandroid.support.v4.app.FragmentTabHost. Un fragment se crea de forma muy parecida a una actividad. También dispone del métodoonCreate(), aunque en este ejemplo no se introduce código. Un fragment también tiene asociada una vista, aunque a diferencia de una actividad, no se asocia en el método onCreate(), si no que dispone de un método especial para esta tarea onCreateView(). 6.Repite los dos pasos anteriores para crear tab2.xml y Tab2.java. 7.Repite de nuevo para crear el layout tab3.xml y la clase Tab3.java. 8.Modifica estos ficheros para que cada layout sea diferente y para que cada fragment visualice el layout correspondiente. 9.Ejecuta el proyecto y verifica el resultado. Unidad 3. Actividades e intenciones En esta unidad seguimos trabajando con el diseño del interfaz de usuario. En lugar de tratar aspectos de diseño visual, como hicimos en la unidad anterior, vamos a tratar temas más relacionados con el código. En concreto nos centraremos en las Actividades y las Intenciones. Estudiaremos también dos herramientas de gran utilidad para cualquier
  • 50. aplicación: la barra de acciones y la definición de las preferencias de configuración. Además se tratará un tipo de vista muy práctica aunque algo compleja de manejar: ListView. Nos vamos a centrar en el ejemplo de aplicación que estamos desarrollando, Asteroides, para añadirle diferentes actividades. A continuación se muestra el esquema de navegación entre actividades que queremos crear: Objetivos:  Describir cómo el interfaz de usuario en una aplicación Android estará formado por un conjunto de actividades.  Mostrar como desde una actividad podemos invocar a otras y cómo podemos comunicarnos con ellas.  Incorporar a nuestras aplicaciones ciertos elementos prácticos como son los menús o las preferencias.  Describir cómo podemos utilizar y crear iconos en nuestras aplicaciones.  Estudiar una vista muy útil en Android: ListView.  Describir el uso de intenciones para invocar actividades estándar en Android. Creación de nuevas actividades El concepto de actividad en Android representa una unidad de interacción con el usuario, es lo que coloquialmente llamamos una pantalla de la aplicación. Una aplicación suele estar
  • 51. formada por una serie de actividades, de forma que el usuario puede ir navegando entre actividades. En concreto, Android suele disponer de un botón (físico o en pantalla) que nos permite volver a la actividad anterior, es decir la actividad que ha creado a la actividad actual. video[Tutorial] Actividades en Android Toda Actividad ha de tener una vista asociada, que será utilizada como interfaz de usuario. Esta vista suele ser de tipoLayout aunque no es imprescindible, como se verá en el siguiente ejemplo. Una aplicación estará formada por un conjunto de actividades independientes, es decir se trata de clases independientes que no comparten variables, aunque todas trabajan para un objetivo común. Otro aspecto importante es que toda actividad ha de ser una subclase de Activity. Las aplicaciones creadas hasta ahora disponían de una única actividad. Esta era creada automáticamente y se le asignaba la vista definida en res/layout/activity_main.xml. Esta actividad era arrancada al comenzar la aplicación. A medida que nuestra aplicación crezca va a ser imprescindible crear nuevas actividades. En este apartado describiremos como hacerlo. Este proceso se puede resumir en cuatro pasos:  — Crea un nuevo Layout para la actividad.  — Crea una nueva clase descendiente de Activity. En esta clase tendrás que indicar que el Layout a visualizar es el desarrollado en el punto anterior.  — Para que nuestra aplicación sea visible será necesario activarla desde otra actividad.  — De forma obligatoria tendremos que registrar toda nueva actividad en AndroidManifest.xml Veamos un primer ejemplo de cómo crear una nueva actividad en la aplicación que estamos desarrollando. Ejercicio paso a paso: Implementación de una caja Acerca de Vamos a crear una caja Acerca de… y visualizarla cuando se pulse el botón adecuado. 1. En primer lugar crea el fichero res/layout/acercade.xml. Para ello pulsa con el botón derecho sobre una carpeta res/layout, seleccionar New > Android XML File e indica en File acercade.xml. 2. Selecciona la lengüeta de edición en XML y copia el siguiente contenido: <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/TextView01" android:layout_width="wrap_content"
  • 52. android:layout_height="wrap_content" android:text="Este programa ha sido desarrollado como ejemplo en el curso de Android para demostrar cómo se pueden lanzar nuevas actividades desde la actividad principal."> </TextView> 3. Creamos ahora una nueva actividad, que será la responsable de visualizar esta vista. Para ello crea el fichero AcercaDe.java.. Abre la carpeta src y pulsa con el botón derecho sobre el nombre de paquete de la aplicación. Seleccionamos New > Class. Reemplaza el código por: package org.example.asteroides; import android.app.Activity; import android.os.Bundle; public class AcercaDe extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acercade); } } 4. Pasemos ahora a crear un método en la actividad principal que será ejecutado cuando sea pulsado el botón Acerca de. public void lanzarAcercaDe(View view){ Intent i = new Intent(this, AcercaDe.class); startActivity(i); } Nota sobre Java: Pulsa Ctrl-Shift-O, en las dos clases modificadas para que automáticamente se añadan los paquetes que faltan. 5. Para asociar este método al botón edita el Layout activity_main.xml. Selecciona el botón Acerca de… y en la vista de Eclipse Properties busca el atributo onClick e introduce el valor lanzarAcercaDe. 6. Pasa a la edición xml pulsando en la lengüeta activity_main.xml y observa como en la etiqueta <Button>correspondiente, se ha añadido el atributo: android:onClick="lanzarAcercaDe" NOTA: En caso de que exista algún recurso alternativo para activity_main.xmlrepite el mismo proceso. 7. Ejecuta ahora la aplicación y pulsa en el botón Acerca de. Observarás que el resultado no es satisfactorio ¿Qué ha ocurrido?
  • 53. El problema es que toda actividad que ha de ser lanzada por una aplicación ha de ser registrada en el fichero AndroidManifest.xml. Para registrar la actividad abre AndroidManifest.xml y selecciona la lengüetaApplication. En Application Nodes pulsa el botón Add… y selecciona Activity. Rellena los campos de la derecha tal y como se muestra a continuación: 8. Guarda AndroidManifest.xml y observa como en este fichero se ha añadido: <activity android:name=".AcercaDe" android:label="Acerca de ..."/> 9. Ejecuta de nuevo el programa. El resultado ha de ser similar al mostrado a continuación:
  • 54. La vista mostrada en el ejemplo anterior no parece muy atractiva. Tratemos de mejorarla aplicando un tema. Como vimos en el capítulo anterior un tema es una colección de estilos que define el aspecto de una activad o aplicación. Puedes utilizar alguno de los temas disponibles en Android o crear el tuyo propio. 10. En este caso utilizaremos uno de los de Android. Para ello abre AndroidManifest.xml y selecciona la lengüeta Application. En Application Nodes pulsa sobre .AcercaDe y a la derecha introduce en el campoTheme: el valor: @android:style/Theme.Dialog. 11. Si lo prefieres edita directamente el fichero AndroidManifest.xml: <activity android:name=".AcercaDe" android:label="Acerca de ..." android:theme="@android:style/Theme.Dialog"/> 12. Ejecuta de nuevo el programa y observa cómo mejora la apariencia:
  • 55. Ejercicio paso a paso: Un escuchador de evento por código Como acabamos de ver en un layout podemos definir el atributo XML android:onClick nos permite indicar un método que será ejecutado al hacer click en una vista. A este método se le conoce como escuchador de evento. Resulta muy sencillo y además está disponible en cualquier desdendiente de la clase View. Sin embargo esta técnica presenta dos inconvenientes. En primer lugar, solo está disponible a partir de la versión 1.6 de Android. En segundo lugar, solo está disponible para el evento onClick(). La clase Viewtiene otros eventos (onLongClick(), onFocusChange(), onKey(),…) para los que no se han definido un atributo xml. Entonces, qué hacemos si queremos trabajar con una versión anterior a 1.6 o definir un evento distinto de onClick(). La respuesta la encontrarás este ejercicio: 1. Abre la clase MainActivity.java y añade las líneas que aparecen subrayadas: public class MainActivity extends Activity { private Button bAcercaDe; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); bAcercaDe =(Button) findViewById(R.id.Button03);
  • 56. bAcercaDe.setOnClickListener(new OnClickListener() { public void onClick(View view) { lanzarAcercaDe(null); } }); } … NOTA: En el capítulo 5 se estudiará con más detalle los escuchadores de evento. Práctica: El botón salir En el layout activity_main.xml hemos introducido un botón con texto “Salir”. Queremos que cuando se pulse este botón se cierre la actividad. Para cerrar una actividad puedes llamar al método finish(); Llamar a este método es equivalente a cuando un usuario pulsa la tecla «retorno». 1. Realiza este trabajo utilizando un escuchador de evento por código. 2. Hazlo ahora con el atributo xml android:onClick. 3. Verifica que el resultado es el mismo en ambos casos. NOTA: No esconveniente que en tus actividades incluyas un botón para cerrarlas. Un dispositivo Android siempre dispone de la tecla «retorno», que tiene la misma función. Solución: 1. Para resolverlo mediante un escuchador por código, añade en el métoco onCreate() de la claseMainActivity el siguiente código: Button bSalir =(Button) findViewById(R.id.button04); bSalir.setOnClickListener(new OnClickListener() { publicvoidonClick(View view) { finish(); } }); 2. Para resolverlo con el atributo onClick, añade en MainActivity el método: public void salir(View view){ finish(); } Y añade el siguiente atributo al botón “Salir” en el layout activity_main.xml: android:onClick="salir"
  • 57. Comunicación entre actividades Cuando una actividad ha de lanzar a otra actividad en muchos casos necesita enviarle cierta información. video[Tutorial] Intercambio de datos entre actividades Android nos permite este intercambio de datos utilizando el mecanismo que es descrito a continuación: Cuando lances una actividad usa el siguiente código: Intent intent = new Intent(this, MI_CLASE.class); intent.putExtra("usuario", "Pepito Perez"); intent.putExtra("edad", 27); startActivity(intent); En la actividad lanzada podemos recoger los datos de la siguiente forma: Bundle extras = getIntent().getExtras(); String s = extras.getString("usuario"); int i = extras.getInt("edad"); Cuando la actividad lanzada termina también podrá devolver datos que podrán ser recogidos por la actividad lanzadora de la siguiente manera. Intent intent = new Intent(this, MI_CLASE.class); startActivityForResult(intent, 1234); ... @Override protected void onActivityResult (int requestCode, intresultCode, Intent data){ if (requestCode==1234 && resultCode==RESULT_OK) { String res = data.getExtras().getString("resultado"); } } En la actividad llamada has de escribir: Intent intent = new Intent(); intent.putExtra("resultado","valor"); setResult(RESULT_OK, intent); finish(); Práctica: Comunicación entre actividades. 1. Crea un nuevo proyecto con nombre ComunicacionActividades. 2. El Layout de la actividad inicial ha de ser similar al que se muestra abajo a la izquierda.
  • 58. 3. Introduce el código para que cuando se pulse el botón “Verificar” se arranque una segunda actividad. A esta actividad se le pasará como parámetro el nombre introducido en el EditText. 4. El Layout correspondiente a la segunda actividad se muestra a la derecha. 5. Al arrancar la actividad el texto del primer TextView ha de modificarse para que ponga “Hola ”+nombre recibido+”¿Aceptas las condiciones?” 6. En esta actividad se podrán pulsar dos botones, de forma que se devuelva a la actividad principal elString “Aceptado” o “Rechazado”, según el botón pulsado. Al pulsar cualquier botón se regresará a la actividad anterior. 7. En la actividad principal se modificará el texto del último TextView para que ponga “Resultado: Aceptado” o “Resultado:Rechazado”, según lo recibido. Añadiendo un menú a una actividad Android permite asignar menús a las actividades, que se despliegan cuando se pulsa la tecla «menú». Este tipo de menús resultan muy interesantes en dispositivos con pantallas pequeñas dado que no ocupan parte de la pantalla, es decir, están ocultos hasta que se pulsa la tecla de «menú». Desde la versión 3.0 ya no es obligatorio que un dispositivo Android diponga de la tecla «menú». No obstante, algunos dispositivos, como los de la marca Samsung, siguen incorporando esta tecla. En la versión 3.0 aparece la barra de acciones, donde se integra el menú de las actividades. Este elemento, que tiene una gran importancia en el diseño del interfaz de usuario en una aplicación Android, será estudiada en el siguiente punto. En este punto estudiaremos el planteamiento anterior a la aparición de la barra de acciones, es decir el menú de actividad. Aunque este tipo de menús pueda parecer un elemento obseleto en una aplicación actual, va ha ser interesante estudiarlo primero. A continuación se justifica por que:  En la actualidad algunos usuarios utilizan terminales con una versión anterior a la 3.0. En estos casos los menús de serán mostrados como se aparecen en este punto.  En algunas actividades no querremos que se muestre la barra de acciones y preferimos utilizar este tipo de menús ocultos. Por ejemplo, si queremos tener toda la pantalla para la actividad o si la estética que buscamos no combina con la barra de acciones.  La barra de acciones es una evolución compatible con los menús de actividad. Estos dos elementos resultan más fáciles de entender si seguimos el orden en que han aparecido.
  • 59. NOTA: En el siguiente vídeo se habla de”menús contextuales”. Este termino no es adecuado dado que puede confundirse con otro tipo de menús. Un termino más preciso sería “menú de actividad”. video[Tutorial] Añadiendo un menú en Android Ejercicio paso a paso: Añadiendo un menú a una actividad Podemos asignar un menú a nuestra actividad de forma muy sencilla. 1. Abre el proyecto de la aplicación. 2. Cuando creamos una nueva aplicación, se crea un menú inicia asociado a la actividadMainActivity. Para modificar este menú abre el fichero res/menú/main.xml. Aparecerá una lista con un solo de elemento de menú, action_settings (Item). NOTA:Cuando quieras crear un nuevo menú para otra actividad, selecciona en el menú de Eclipse File > New > Android XML File. y selecciona en el campo Resource Type: Menu. 3. El elemento de menú creado por defecto no nos interesa. Para eliminarlo selecciónalo, pulsando sobre action_settings (Item), y haz clic en el botón Remove. 4. Añade un elemento de tipo Item. Introduce en el campo Id el valor @+id/config, en el campo Title el valor Configuración. y en el campo Icon @android:drawable/ic_menu_preferences. 5. Repite el proceso para introducir un nuevo ítem con Id tomando el valor @+id/acercaDe, Title con el valor Acerca de … e Icon con el valor @android:drawable/ic_menu_info_details. 6. Pulsa la lengüeta .xml. El fichero xml resultante se muestra a continuación:
  • 60. <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:title="Configuración" android:id="@+id/config" android:icon="@android:drawable/ic_menu_preferences"/> <item android:title="Acerca de..." android:id="@+id/acercaDe" android:icon="@android:drawable/ic_menu_info_details"/> </menu> La apariencia de este menú se muestra a continuación. Esta apariencia puede cambiar dependiendo de la versión de Android. 7. Para activar el menú has de introducir el siguiente código al final de MainActivity.java: @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); return true; /** true -> el menú yaestá visible */ } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.acercaDe: lanzarAcercaDe(null); break; } return true; /** true -> consumimos el item, no se propaga*/ } 8. Ejecuta el programa y pulsa la tecla «menú» del terminal. En la parte inferior de la pantalla ha de aparecer los dos ítems de menu como se muestra en la figura anterior. La barra de acciones (ActionBar) video[Tutorial] Añadiendo un menú en Android Desde la versión 3.0, se introdujo en Android un nuevo elemento en la interfaz de usuario: la barra de acciones o ActionBar. Situada en la parte superior de la pantalla, fue creada para que el usuario tuviera una experiencia unificada a través de las distintas aplicaciones. La barra de acciones aglutina varios elementos; los más habituales son el icono de la aplicación con su nombre y los botones de acciones frecuentes. Las acciones menos utilizadas se sitúan en un menú desplegable, que se abrirá desde el botón «Overflow». Si la aplicación dispone de pestañas (tabs), estas podrán situarse en la barra de tareas.
  • 61. También pueden añadirse otros elementos como listas desplegables y otros tipos de widgets incrustados, como el widget de búsqueda que veremos más adelante. En caso de disponer de menos tamaño de pantalla el sistema puede redistribuir los elementos y pasar alguna acción al menú de «Overflow». Por ejemplo, en un móvil el ActionBar anterior se podría ver de la siguiente manera: Los dispositivos anteriores a la 3.0 requerían una tecla física para mostrar el menú de la actividad. Sin embargo, con esta versión dicha tecla deja de ser un requisito de los terminales y los menús pasan a mostrarse en la barra de acciones. En los dispositivos que sí que dispongan de este botón físico, es posible que los tres puntos que representan el menú de «Overflow» no se representen en la barra de acciones. En este caso tienes que pulsar el botón físico para desplegar este menú. La barra de acciones se configura igual que los menús disponibles desde la primera versión. Es decir, a través de ficheros XML de menús, almacenados en res/menu. Esto permite diseñar el menú de una aplicación de la forma convencional. Cuando la aplicación se ejecute en una versión inferior a la 3.0, el menú se mostrará de forma tradicional. Cuando el usuario pulse la tecla «menú» aparecerá: Pero, en caso de disponer de una versión 3.0 o superior, se mostrará en la barra de acciones. Añadir un ActionBar a la aplicación es muy sencillo. Es más, gracias a que se utiliza la misma herramienta que para mostrar menús en dispositivos con versiones anteriores, todas las opciones delActionBar estarán disponibles independientemente de la versión que se esté utilizando. Por lo tanto, no hay que realizar ningún paso para que se visualice la barra de acciones. Todos los temas de Android a partir de la versión 3.0 incorporan por defecto la barra de acciones visible (menos los que acaban enNoActionBar). Si se desea ocultar la barra de acciones desde código es muy sencillo; pero mostrarla una vez aplicado un estilo que la deshabilite es imposible. Desde finales de 2013 también podemos utilizar ActionBar en versiones anteriores a la 3,0 gracias a la aparición de una librería de compatibilidad. Veremos como realizarlo en uno de los siguientes ejercicios. Ejercicio paso a paso: Añadiendo un ActionBar a nuestra aplicación. 1. Reemplaza el contenido del fichero res/menu/main.xml por: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:title="Configuración" android:id="@+id/config" android:icon="@android:drawable/ic_menu_preferences" android:orderInCategory="95" android:showAsAction="ifRoom"/>
  • 62. <item android:title="Acerca de..." android:id="@+id/acercaDe" android:icon="@android:drawable/ic_menu_info_details" android:showAsAction="ifRoom|withText"/> <item android:title="Buscar" android:id="@+id/menu_buscar" android:orderInCategory="90" android:icon="@android:drawable/ic_menu_search" android:showAsAction="always|collapseActionView"/> </menu> Este fichero XML es el que define los iconos y acciones a mostrar. Como ya hemos dicho, para los dispositivos con una versión 3.0 o superior, este menú se muestra en la barra de acciones. Las acciones que indiquen en el atributo showAsAction la palabra always serán mostrados siempre, sin importar si caben o no. El uso de estas acciones debería limitarse a unas pocas, o incluso mejor si no hay ninguna, ya que al forzar que se visualicen todas al mismo tiempo podrían verse incorrectamente. Las acciones que indiquen ifRoom serán mostradas en la barra de acciones si hay espacio disponible, y serán movidas al menú de Overflow si no lo hay. En esta categoría se deberían encontrar la mayoría de acciones. Si se indica never la acción nunca se mostrará en la barra de acciones, sin importar el espacio disponible. En este grupo se deberían situar acciones como modificar las preferencias, que deben estar disponibles al usuario; pero no visibles en todo momento. Las acciones son ordenadas de izquierda a derecha según lo indicado en orderInCategory, con las acciones con un número más pequeño más a la izquierda. Si todas las acciones no caben en la barra, las que tienen un número menor son movidas al menú de Overflow. 2. Ejecuta la aplicación; podrás ver como aparece la barra de acciones en la parte de arriba, con los botones que hemos definido. Creación y uso de iconos En el apartado anterior hemos creado un menú que hacía uso de dos iconos. Se utilizaban iconos disponibles en el sistema Android, es decir, se han utilizado recursos del sistema Android. Otra alternativa es crear tus propios iconos y almacenarlos en la carpeta res/drawable. video[Tutorial] Añadiendo iconos en Android tipo de iconos finalidad Ejemplos
  • 63. lanzadores representa la aplicación en la pantalla principal del dispositivo Menú se muestran cuando presione el botón Menú. Cada actividad puede definir su propio menú. barra de acciones a partir de la versión 3.0 con el aumento de pantalla de la tabletas las actividades pueden disponer de una barra de iconos siempre visible. barra de estado barra con pequeños iconos que nos alertan de notificaciones (ver CAPÍTULO 8) Pestañas Las pestañas (Tabs) nos permiten seleccionar entre varias vistas. Otros También es muy frecuente el uso de iconos en cuadros de dialogo y en ListView. Tabla 2: Tipos de iconos en Android. Si estás interesado en utilizar iconos disponibles en el sistema, encontrarás el inconveniente de no poder seleccionar el que te interese de forma sencilla. Recuerda como en el punto 6 del último ejercicio, cuando introducías el campo Icon en la definición de un ítem de menú, no disponía del botón Browse… para poder seleccionar el icono desde una lista. Para conocer los iconos disponibles te recomendamos que utilices el primer enlace de la lista mostrada a continuación. Si por el contrario decides diseñar tus propios iconos has de tener en cuenta algunos aspectos. En primer lugar, recuerda que Android ha sido concebido para ser utilizado en dispositivos con gran varidad de densidades gráficas. Este rango puede ir desde 100 pixeles/pulgada (ldpi) hasta 340 pixeles/pulgada (xhdpi). Por lo tanto, resulta interesante que plantees tus diseños con una resolución como mínimo de 300 pixeles/pulgada. Cuando se represente en un dispositivo el sistema reajustará el tamaño del icono para que se ajuste al espacio disponible y, por supuesto, siempre es conveniente realizar una reducción en lugar de tener que ampliar. Ahora bién, en muchos casos este reajuste automático de tamaño puede no ser se satisfactorio (en el siguiente ejercicio se muestra un ejemplo). En estos casos, podremos hacer usos de los recursos alternativos y crear diferentes iconos para diferentes densidades gráficas. Para ayudarte en esta tarea puedes utilizar la herramienta Android Asset Studio que se incluye en la siguiente lista de enlaces. En segundo lugar, tu aplicación va a ser ejecutada dentro de un sistema donde se utilizan ciertas guias de estilo. Si quieres que tus iconos no desentonen lee la documentación que se indica a continuación.
  • 64. Enlaces de interés: Lista de recursos drawable: En la documentación oficial de Android no aparece un listado con los recursos disponibles. Para ver gráficamente todos los recursos drawable del sistema puedes acceder a la siguiente página: http://androiddrawableexplorer.appspot.com/ Android Asset Studio:Puedes crear tus propios iconos de forma sencilla utilizando la siguiente herramienta online: http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html Guía de estilo para iconos: La siguiente página describe las guías de estilo para los iconos en las distintas versiones de Android: http://developer.android.com/guide/practices/ui_guidelines/icon_design.html Ejercicio paso a paso: Creación de iconos personalizados Si te gusta el diseño o lo consideras interesante para tu formación, pueden resultar de gran utilidad las herramientas descritas anteriormente. Vemos un ejemplo práctico: El diseñador gráfico de nuestra empresa, nos acaba de pasar el icono asociado para iniciar a la aplicación que estamos diseñando (launcher Icon). Pulsa para descargar el grafico grafico_aplicacion.PNG El problema es que no estamos seguros de que se va a ver correctamente para las diferentes densidades gráficas que podemos encontrar en los dispositivos Android. Para asegurarnos que esto sea así realizaríamos los siguientes pasos: 1. Descarga el gráfico anterior de www.androidcurso.com y llámale icon.png. 2. Accede a Android Asset Studio:
  • 65. http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html 3. Selecciona la opción: Launcher icons 4. Pulsa sobre el botón Image y selecciona el fichero anterior. 5. En la parte inferior de la página podrás previsualizar como quedarán las imágenes para las cuatro densidades gráficas de Android. 6. El resultado solo es aceptable para la opción xhdpi. En el resto de los casos ha desaparecido alguna línea o el texto no se lee. Va a ser imprescindible retocar estos iconos. 7. Descarga el fichero pulsando en 8. Retoca el icono hdpi para que se vean todas las líneas azules. 9. Retoca el icono mdpi y ldpi para que se pueda leer el texto “Aplicación”. 10. Asigna los iconos retocados a las carpetas adecuadas (res/drawable) de una aplicación (por ejemplo la creada en la sección “Comunicación entre actividades”). 11. Visualiza el resultado instalando la aplicación en diferentes dispositivos con diferentes densidades gráficas. Práctica: Creación de iconos para la aplicación 1. Dibuja o busca en Internet un gráfico que sea adecuado para usar como icono de inicio en la aplicación. 2. Repite los pasos indicados en el ejercicio anterior para crear los iconos en las diferentes densidades gráficas. Añadiendo preferencias de usuario Android nos facilita la configuración de nuestro programa, al permitir añadir una lista de preferencias que el usuario podrá modificar. Las preferencias también pueden ser utilizadas para que tu aplicación almacene de forma permanente información. En la unidad 9 se estudiará cómo realizar esta función. video[Tutorial] Añadir preferencias en Android
  • 66. Ejercicio paso a paso: Añadiendo preferencias a Asteroides 1. Abre el proyecto Asteroides. 2. Pulsa con el botón derecho sobre la carpeta res y selecciona la opción New > Other… Selecciona Android > Android XML File. 3. Completa los siguientes campos Resource Type: Preference, File: preferencias.xml. Se creará el fichero res/xml/preferencias.xml. 4. Selecciona la lengüeta preferencias.xml para editar el fichero en xml. 5. Introduce el siguiente código: <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:key="preferencias_principal" > <CheckBoxPreference android:key="musica" android:title="Reproducir música" android:summary="Se reproduce música de fondo"/> <ListPreference android:key="graficos" android:title="Tipo de gráficos" android:summary="Se escoge la representación de gráficos" android:entries="@array/tiposGraficos" android:entryValues="@array/tiposGraficosValores" android:defaultValue="1"/> <EditTextPreference android:key="fragmentos" android:title="Número de Fragmentos" android:summary="En cuantos trozos se divide un asteroide" android:defaultValue="3"/> </PreferenceScreen> El resultado que obtendremos se muestra a continuación:
  • 67. 6. Para almacenar los valores del desplegable has de crear el fichero /res/values/arrays.xml con el siguiente contenido: <resources> <string-array name="tiposGraficos"> <item>vectorial</item> <item>bitmap</item> <item>3D</item> </string-array> <string-array name="tiposGraficosValores"> <item>0</item> <item>1</item> <item>2</item> </string-array> </resources> 7. En lugar de trabajar directamente con xml. También puedes introducir las distintas preferencias utilizando la lengüetaStructure. Investiga esta opción. 8. Crea ahora una nueva clase Preferencias.java con el siguiente código: package org.example.asteroides; public class Preferencias extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferencias); } } Nota sobre Java:Pulsa Ctrl-Shift-O, para que automáticamente se añadan los paquetes que faltan.
  • 68. NOTA: Desde el nivel de API 11 el método addPreferencesFromResource()ha sido marcado como obsoleto. En lugar de usar la clase FragmentActivityse recomienda utilizar PreferenceFragments. El uso de fragments será estudiado más adelante. 9. No hay que olvidar registrar toda nueva actividad en AndroidManifest.xml. 10. Añade a Asteroides.java el método lanzarPreferencias(). Este método ha de tener el mismo código quelanzarAcercaDe() pero lanzando la actividad Preferencias. 11. En el Layout activity_main.xml añade al botón con texto “Configurar” en el atributo onClick el valorlanzarPreferencias. 12. Para activar la configuración desde la opción de menú añade el siguiente código en el ficheroAsteroides.java en el método onOptionsItemSelected() dentro del switch. case R.id.config: lanzarPreferencias(null); break; 13. Arranca la aplicación y verifica que puedes lanzar las preferencias mediante las dos alternativas. Organizando preferencias Cuando el número de preferencias es grande resulta interesante organizarlas de forma adecuada. Una posibilidad consiste en dividirlas en varias pantallas. De forma que cuando se seleccione una opción en la primera pantalla, se abra una nueva pantalla de preferencias. Para organizar las preferencias de esta forma usa el siguiente esquema: <PreferenceScreen> <CheckBoxPreference …/> <EditTextPreference …/> … <PreferenceScreen android:title=”Modo multijugador”> <CheckBoxPreference …/> <EditTextPreference …/> … </PreferenceScreen> </PreferenceScreen> Práctica: Organizando preferencias(I) 1. Crea una nueva lista de preferencias <PreferenceScreen> dentro de la lista de preferencias del fichero res/xml/preferencias.xml. 2. Asígnale al parámetro android:title el valor “Modo multijugador”. 3. Crea tres elementos dentro de esta lista: Activar multijugador, Máximo de jugadores y Tipo de conexión. Para este ultimo han de poder escogerse los valores: Bluetooth, Wi-Fi e Internet. Otra alternativa para organizar las preferencias consiste en agruparlas por categorías. Con esta opción se visualizarán en la misma pantalla, pero separadas por grupos. Has de seguir el siguiente esquema: <PreferenceScreen>
  • 69. <CheckBoxPreference …/> <EditTextPreference …/> … <PreferenceCategory android:title=”Modo multijugador”> <CheckBoxPreference …/> <EditTextPreference …/> .. … </PreferenceCategory> </PreferenceScreen> A continuación se representa la forma en la que Android muestra las categorías: Práctica: Organizando preferencias(II) 1. Modifica la práctica anterior para que en lugar de mostrar las propiedades en dos pantallas, las muestre en una sola, tal y como se muestra en la imagen anterior. Como se almacenan las preferencias de usuario Si un usuario modifica el valor de una preferencia, este quedará almacenado de forma permanente en el dispositivo. Para conseguir esta persistencia Android almacena las preferencias seleccionadas en un fichero XML dentro de la
  • 70. carpeta data/data/nombre.del.paquete/files/shared_prefs. Donde nombre.del.paquete ha de ser reemplazado por el paquete de la aplicación. El nombre del fichero para almacenar las preferencias de usuario ha de ser siempre nombre.del.paquete_preferences.xml.Esto significa que solo puede haber unas preferencias de usuario por aplicación. Como se estudiará en el capítulo 9 pueden haber otros ficheros de preferencia, pero a diferencia de las preferencias de usuario no pueden ser editadas directamente por el usuario sino que hay que acceder a ellas por código. Ejercicio paso a paso: Donde se almacenan las preferencias de usuario Veamos donde se han almacenado las preferencias que acabamos de crear: 1. Para navegar por el sistema de ficheros de un dispositivo (tanto virtual como real) accede al menú Window > Show View > Others… > Android > File Explorer. 2. Busca el siguiente fichero: /data/data/org.examples.asteroides/shared_prefs/ org.examples.asteroide_preferences.xml 3. Pulsa el botón del disquete para descargar el fichero en tu PC. 4. Visualiza su contenido. Tiene que ser similar a: <map> <boolean name="musica"value="true" /> <string name="graficos">1</string> <string name="fragmentos">3</string> </map> Accediendo a los valores de las preferencias Por supuesto, será necesario acceder a los valores de las preferencias para alterar el funcionamiento de nuestra aplicación. El siguiente ejemplo nos muestra cómo realizarlo: public void mostrarPreferencias(){ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); String s = "música: "+ pref.getBoolean("musica",true) +", gráficos: " +
  • 71. pref.getString("graficos","?"); Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); } La función comienza creando el objeto pref de la clase SharedPreferences y le asigna las preferencias definidas para la aplicación. A continuación crea el String s y le asigna los valores de dos de las preferencias. Se utilizan los métodos pref.getBoolean() y pref.getString(), que disponen de dos parámetros: el valor dekeyque queremos buscar ("musica" y "graficos") y el valor asignado por defecto en caso de no encontrar esta key. Finalmente se visualiza el resultado utilizando la clase Toast. Los tres parámetros indicados son el contexto (nuestra actividad), el String a mostrar y el tiempo que se estará mostrando esta información. Ejercicio paso a paso: Accediendo a los valores de las preferencias 1. Copia la función anterior en la clase Asteroides. Añade el parámetro que se muestra a continuación mostrarPreferencias(View view). 2. Asígnala al atributo onClick del botón Jugar el método anterior. 3. Visualiza también el resto de las preferencias que hayas introducido. Creando actividades en Mis Lugares Creando la actividad VistaLugar de Mis Lugares En este apartado crearemos la actividad VistaLugar en la aplicación Mis Lugares. Esta actividad nos mostrará la información que hemos almacenado de un determinado lugar y nos permitirá realizar gran cantidad de acciones sobre este lugar (mostrar en mapa, llamar por teléfono, compartir en redes sociales, etc.). Desde esta actividad podremos cambiar algunos valores de modificación frecuente. En concreto: la valoración, fecha de visita y fotografía. Ejercicio paso a paso: Creación de Ia actividad VistaLugar. 1. Abre el proyecto MisLugares. 2. Copia dentro de la carpeta res/drawable los gráficos que encontrarás en el siguiente fichero:http://www.dcomg.upv.es/~jtomas/android/ficheros/mislugares.zip Crea un nuevo layout con nombre vista_lugar.xml. Copia el siguiente código para usarlo como base: <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/scrollView1"
  • 72. android:layout_width="match_parent" android:layout_height="wrap_content" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/nombre" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center" android:text="Nombres del lugar" android:textAppearance="?android:attr/textAppearanceLarge" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:id="@+id/logo_tipo" android:layout_width="40dp" android:layout_height="40dp" android:contentDescription="logo del tipo" android:src="@drawable/otros" /> <TextView android:id="@+id/tipo" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:text="tipo del lugar" /> </LinearLayout> … <RatingBar android:id="@+id/valoracion" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_toRightOf="@+id/foto" android:rating="3" /> <FrameLayout android:layout_width="match_parent"
  • 73. android:layout_height="wrap_content" > <ImageView android:id="@+id/foto" android:layout_width="match_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:contentDescription="fotografía" android:src="@drawable/foto_epsg" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" > <ImageView android:layout_width="40dp" android:layout_height="40dp" android:contentDescription="logo camara" android:src="@android:drawable/ic_menu_camera" /> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:contentDescription="logo galeria" android:src="@android:drawable/ic_menu_gallery" /> </LinearLayout> </FrameLayout> </LinearLayout> </ScrollView> Observa como el elemento exterior es un ScrollView esto es conveniente cuando pensemos que los elementos de layout no cabrán en la pantalla. En este caso el usuario podrá desplazar verticalmente el layout arrastrando con el dedo. Dado que algunas pantallas pueden ser muy pequeñas la mayoría de diseños han de incorporar un ScrollView. Dentro de este elemento tenemos un LinearLayout para organizar las vistas verticalmente. La primera vista es un TextView cuyo id es nombre. Se ha asignado un valor para text inicial, que será reemplazado por el nombre del lugar. La única función que tiene este texto inicial es ayudarnos en el diseño. El siguiente elemento es un LinearLayout vertical que contiene un ImageView y un TextView. Este elemento será utilizado para indicar el tipo de lugar. Los puntos suspensivos indican el lugar donde tendrás que insertar el resto de elementos que no se han incluido (dirección, teléfono, etc.). El siguiente elemento que se incluye es un RatingBar donde podremos introducir una valoración del lugar. El último elemento es un FrameLayout que permite superponer varias vistas. Serán dibujadas en el orden en que las indicamos. En el fondo se dibuja unImageView con una fotografía de la EPSG. El atributo adjustViewBounds indica que la imagen sea escalada para ocupar todo el espacio disponible. Sobre la fotografía se dibujará
  • 74. un LinearLayoutcon dos ImageView. Estos botones permitirán cambiar la fotografía desde la cámara o desde la galería. 4. Reemplaza los puntos suspensivos por los elementos que faltan para obtener la apariencia mostrada al principio de este punto. Utiliza los recursos del sistema mostrados en la siguiente tabla. Identifica dada TextView con el id que se indica. Recurso para ImageView Id para TextView @android:drawable/ic_menu_myplaces @+id/direccion @android:drawable/ic_menu_call @+id/telefono @android:drawable/ic_menu_mapmode @+id/url @android:drawable/ic_menu_info_details @+id/comentario @android:drawable/ic_menu_my_calendar @+id/fecha @android:drawable/ic_menu_recent_history @+id/hora 5. Crea la clase VistaLugar y reemplaza el código por el siguiente: public class VistaLugar extends Activity { private long id; private Lugar lugar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.vista_lugar); Bundle extras = getIntent().getExtras(); id = extras.getLong("id", -1); lugar = Lugares.elemento((int) id); TextView nombre = (TextView) findViewById(R.id.nombre); nombre.setText(lugar.getNombre()); ImageView logo_tipo = (ImageView) findViewById(R.id.logo_tipo); logo_tipo.setImageResource(lugar.getTipo().getRecurso()); TextView tipo = (TextView) findViewById(R.id.tipo); tipo.setText(lugar.getTipo().getTexto()); TextView direccion = (TextView) findViewById(R.id.direccion); direccion.setText(lugar.getDireccion()); TextView telefono = (TextView) findViewById(R.id.telefono); telefono.setText(Integer.toString(lugar.getTelefono())); TextView url = (TextView) findViewById(R.id.url); url.setText(lugar.getUrl()); TextView comentario = (TextView)
  • 75. findViewById(R.id.comentario); comentario.setText(lugar.getComentario()); TextView fecha = (TextView) findViewById(R.id.fecha); fecha.setText(DateFormat.getDateInstance().format( new Date(lugar.getFecha()))); TextView hora = (TextView) findViewById(R.id.hora); hora.setText(DateFormat.getTimeInstance().format( new Date(lugar.getFecha()))); RatingBar valoracion = (RatingBar) findViewById(R.id.valoracion); valoracion.setRating(lugar.getValoracion()); valoracion.setOnRatingBarChangeListener( newOnRatingBarChangeListener() { @Override public void onRatingChanged(RatingBar ratingBar, float valor, boolean fromUser) { lugar.setValoracion(valor); } }); } } Nota sobre Java: Pulsa Ctrl-Shift-O, para que automáticamente se añadan los imports con los paquetes que faltan. Dos clases aparecen en varios paquetes, selecciona java.text.DateFormat y java.util.Date. El método onCreate() será ejecutado cuando se cree la actividad y en el tenemos que asociar un layout (setContentView(R.layout.vista_lugar)) e inicializar todos sus valores. Lo primero que se hace es averiguar el id del lugar a mostrar, que ha sido pasado en un extra. A partir de este id obtenemos el objeto Lugar a mostrar. Tanto este objeto como el id son almacenados en variables globales para que puedan ser accedidas desde cualquier método de la actividad. Observa cómo se obtiene un objeto de cada uno de los elementos de la vista utilizando el métodofindViewById(). A continuación este objeto es modificado según el valor del lugar que estamos representando. Al final se realiza una acción especial con el objeto valoracion. Utilizando el métodosetOnRatingBarChangeListener() para asignarle un escuchador de eventos al RatingBar que es creado allí mismo. Este evento será activado cuando el usuario modifique la valoración asignada. El código a ejecutar consiste en llamar a al método setValoracion() del objeto lugar con la nueva valoración. 6. En la primera unidad se creó el proyecto MisLugaresJava. Abre este proyecto y selecciona las clases GeoPunto, Lugar, Lugares y TipoLugar (Puedes seleccionar varios ficheros manteniendo la tecla Ctrl pulsada). Con el botón derecho selecciona la opción Copy. Con el botón derecho pulsa sobre MisLugares/srv/com.example.mislugares y selecciona la opción Paste.
  • 76. 7. Abre la clase TipoLugar y asigna un recurso drawable a cada tipo de lugar. Puedes utilizar la opción de autocompletar, es decir, escribe R.drawable. y espera a que el sistema te dé una alternativa. public enum TipoLugar { OTROS ("Otros", R.drawable.otros), RESTAURANTE ("Restaurante", R.drawable.restaurante), BAR("Bar", R.drawable.bar), … 8. Añade en la clase ActivityMain el siguiente método: public void lanzarVistaLugar(View view){ Intent i = new Intent(this, VistaLugar.class); i.putExtra("id", (long)0); startActivity(i); } Este método lanzará la actividad VistaLugar pasándole como id del lugar a visualizar siempre 0. Más adelante mostraremos algunas alternativas para que el usuario pueda seleccionar el lugar a mostrar. 9. En el layout/activity_main.xml añade el atributo onClick en el primer botón. <Button … android:onClick="lanzarVistaLugar" android:text="@string/accion_mostrar" /> 10. Repite este proceso en layout-land/activity_main.xml. 11. Ejecuta la aplicación. Aparecerá un error cuando pulses en el botón Mostrar Lugares. Siempre un error en ejecución es el momento de visualizar el LogCat. No es sencillo analizar la información que se muestra, pero es muy importante que te acostumbres a buscar la causa del problema en el LogCat. En este caso la información clave se muestra a continuación: 12. Para resolver el error en ejecución registra la nueva actividad en AndroidManifest.xml. 13. Verifica que la aplicación muestra siempre el primer lugar. Ejercicio paso a paso: Un cuadro de dialogo para indicar el id de lugar Tras realizar el ejercicio anterior comprobarás que siempre se visualiza el lugar con id = 0 (i.putExtra("id", (long)0)). En este ejercicio vamos a introducir un cuadro de dialogo que permita introducir al usuario el id que desea visualizar.
  • 77. Ha de quedar claro que esta es una forma más correcta de diseñar el interfaz de usuario. En la siguiente unidad reemplazaremos este cuadro de dialogo por un ListView. 1. Abre la clase MainActivity del proyecto MisLugares. 2. Reemplaza el método por el lanzar VistaLugar() siguiente: public void lanzarVistaLugar(View view){ final EditText entrada = new EditText(this); entrada.setText("0"); new AlertDialog.Builder(this) .setTitle("Selección de lugar") .setMessage("indica su id:") .setView(entrada) .setPositiveButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { long id = Long.parseLong(entrada.getText().toString()); Intent i = new Intent(MainActivity.this, VistaLugar.class); i.putExtra("id", id); startActivity(i); }}) .setNegativeButton("Cancelar", null) .show(); } Nota sobre Java: En Java es posible crea un objeto sin que este disponga de un identificador de objeto. Este tipo de objeto se conoce como objeto anónimo. El código mostrado a continuación a la derecha es equivalente al de la izquierda. Clase objeto = new Clase(); newClase().metodo(); objeto.metodo(); Un objeto anónimo no tiene identificador por lo que solo puede ser usado donde es creado. En el método anterior se ha creado un objeto anónimo de la clase AlertDialog.Builder. Observa cómo no se llama a un método, sino a una cadena
  • 78. de métodos. Esto es posible porque los métodos de la claseAlertDialog.Builder retornan el objeto que estamos creando. Por lo tanto, cada método es aplicado al objeto devuelto por el método anterior. En Android puedes usar la clase AlertDialog para crear un cuadro de dialogo configurable. Si te fijas en la captura anterior están formados por cuatro elementos, de arriba abajo: título, mensaje, vista y botones. Estos elementos pueden ser configurados mediante los método setTitle(), setMessage(), setView(), setPositiveButton() y setNegativeButton(). La vista que se utiliza en este diálogo es un EditText, inicializado con un texto. En caso de necesitar varias entradas se puede crear una vista de tipo layout, que contendría estas entradas. Se han introducido dos botones, indicando el texto del botón y un escuchador de evento que será llamado cuando se pulse el botón. Finalmente se llama al método show() para que se visualice el cuadro de diálogo. 3. Verifica que funciona correctamente. Pero cuidado, no se verifica que el id sea válido, por lo que ocurrirá un error si es incorrecto. Práctica: Ocultar elementos en VistaLugar En ocasiones no se dispondrá de parte la información de un lugar. En estos casos, puede resultar más conveniente desde un punto de vista estético, no mostrar cambios sin información en la actividadVistaLugar. Por ejemplo, si el campo de teléfono es igual a 0, podríamos usar el siguiente código para que no se muestre: if (lugar.getTelefono() == 0) { findViewById(R.id.p_telefono).setVisibility(View.GONE); } else { TextView telefono = (TextView) findViewById(R.id.telefono); telefono.setText(Integer.toString(lugar.getTelefono())); } Para ocultarlo, en el layout p_telefono, ponemos el valor propiedad visivility al valor GONE. Este atributo es aplicado a cualquier tipo de vista. Otros posibles valores para este atributo son VISIBLE eINVISIBLE. Tanto con GONE como con INVISIBLE la vista no se verá. Pero con INVISIBLE el espacio ocupado por la vista se mantiene, mientras que con GONE este espacio es eliminado. Trata de realizar un proceso similar a este para los campos dirección, telefono, url y comentario. Ejercicio paso a paso: Añadir una barra de acciones a VistaLugar
  • 79. En este ejercicio vamos a añadir a la actividad un menú a la barra de acciones similar al que se muestra a continuación: 1. En primer lugar crea el fichero res/menu/vista_lugar.xml que contendrá las acciones a mostrar. Para ello pulsa con el botón derecho sobre una carpeta del proyecto MisLugares, seleccionar New > Android XML File e indica en Resource Type: Menu y en File: vista_lugar. 2. Selecciona la lengüeta de edición en XML y copia el siguiente código: <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/accion_compartir" android:title="compartir" android:icon="@android:drawable/ic_menu_share" android:orderInCategory="10" android:showAsAction="ifRoom"/> <item android:id="@+id/accion_llegar" android:title="cómo llegar" android:icon="@android:drawable/ic_menu_directions" android:orderInCategory="20" android:showAsAction="ifRoom"/> <item android:id="@+id/accion_editar" android:title="editar" android:icon="@android:drawable/ic_menu_edit" android:orderInCategory="30" android:showAsAction="ifRoom"/> <item android:id="@+id/accion_borrar" android:title="borrar" android:icon="@android:drawable/ic_menu_delete" android:orderInCategory="40" android:showAsAction="ifRoom"/> </menu> 3. En la clase VistaLugar añade los siguientes métodos: @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.vista_lugar, menu); returntrue; }
  • 80. @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.accion_compartir: return true; case R.id.accion_llegar: return true; case R.id.accion_editar: return true; case R.id.accion_borrar: Lugares.borrar((int) id); finish(); return true; default: return super.onOptionsItemSelected(item); } } 4. Ejecuta la aplicación y borra un lugar. Verifica como si tratas de visualizar el mismo id ahora se muestra el siguiente lugar. Práctica: Un cuadro de dialogo para confirmar el borrado Un usuario podría pulsar por error el botón de borra, por lo que sería muy conveniente pedir una confirmación antes de borrar. 1. Crea un nuevo método en la actividad. 2. Modifica el código asociado a case R.id.accion_borrar: para que se llame a este método. 3. En el método crea un cuadro de dialogo siguiendo el esquema planteado en el ejercicio anterior. Puede ser similar al siguiente. Creando la actividad EdicionLugar de Mis Lugares En este apartado crearemos otra actividad en la aplicación Mis Lugares, EdicionLugar. Esta actividad nos permitirá modificar la mayoría de valores asignados a un lugar (se excluyen los valores que se modifican desde VistaLugar: Valoración, fecha y foto):
  • 81. Práctica: Creación de la actividad EdicionLugar 1. Abre el proyecto MisLugares y verifica que existe el layout edición_lugar.xml. En caso contrario realiza la práctica Un formulario para introducir nuevos lugares (http://www.androidcurso.com/index.php/115). 2. Crea la clase EdicionLugar. Y copia en esta clase los atributos y el método onCreate() de la clase VistaLugar. 3. Añade las siguientes atributos a la clase: private EditText nombre; private Spinner tipo; private EditText direccion; private EditText telefono; private EditText url; private EditText comentario; De esta forma estos seis objetos serán accesibles desde cualquier método de la clase, en lugar de estar declarados solo en el método onCreate(). 4. Reemplaza la vista a mostrar en setContentView() por la adecuada. 5. El paso de parámetros puede realizarse de la misma forma. 6. La creación e inicialización de los objetos nombre, direccion, telefono, url y comentariopuede realizarse de forma similar al copiado. Pero ahora, no han de ser declarados en el método, al estar declarados como atributos. Por lo tanto, has de eliminar el TextView inicial de cada objeto. Además, estos objetos ahora son de la clase EditText en lugar de TextView. Por lo tanto, reemplaza(TextView) por (EditText). 7. Puedes eliminar el resto del código de este método. 8. En la clase VistaLugar dentro del método onOptionsItemSelected(), añade el código necesario para que se abra la actividad que acabas de crear. 9. Ejecuta el proyecto. Pero antes, piensa si falta alguna acción por realizar. Ejercicio paso a paso: Inicializar el Spinner en EdicionLugar Como has podido verificar en la ejecución anterior el Spinner (lista desplegable) no muestra ningún valor. En este ejercicio trataremos que funcione adecuadamente: 1. Añade el siguiente código el método onCreate(): Spinner tipo = (Spinner) findViewById(R.id.tipo); ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this,
  • 82. android.R.layout.simple_spinner_item, TipoLugar.getNombres()); adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); tipo.setAdapter(adaptador); tipo.setSelection(lugar.getTipo().ordinal()); Para inicializar los valores que puede tomar un Spinner necesitamos una clase especial conocida como Adapter. Esta clase será estudiada en la siguiente unidad. De momento solo adelantar que un Adapter va a crear una lista de vistas, inicializándolas con unos valores determinados. La claseArrayAdapter<String> es un tipo de Adapter que permite inicializar sus valores a partir de un array deString. Su constructor necesita tres parámetros: un contexto (usamos la actividad actual), una vista para mostrar elemento (usamos un vista definida en el sistema) y un array de String. Para el último parámetro necesitamos un array con todos los valores que puede tomar el enumerado TipoLugar.Para obtener este array se define un nuevo método que se mostrará a continuación. El siguiente método, setDropDownViewResource(), permite indicar una vista alternativa que será usada cuando se despliegue el Spinner. En la versión 4.x esta vista es un poco más grande que la usada en el método anterior para poder seleccionarla cómodamente con el dedo. En la versión 2.x muestra círculos seleccionables a la derecha de cada elemento. Este código concluye asignando el adaptador al Spinner y poniendo un valor inicial según el tipo actual de lugar. 2. Añade el siguiente método a la clase TipoLugar: public static String[] getNombres() { String[] resultado = new String[TipoLugar.values().length]; for(TipoLugar tipo : TipoLugar.values()) { resultado[tipo.ordinal()] = tipo.texto; } return resultado; } 3. Ejecuta la aplicación y verifica que la lista desplegable funciona correctamente.. Práctica: Añadir una barra de acciones a EdicionLugar En esta práctica vamos a añadir a la actividad un menú en la barra de acciones similar al que se muestra a continuación: 1. Crea un nuevo recurso de menú con las opciones que se indican. 2. Asocia este menú a la actividad EdicionLugar con el método onCreateOptionsMenu(). 3. Crea el método onOptionsItemSelected() de manera que cuando se seleccione la acciónGuardar se ejecute el siguiente código:
  • 83. lugar.setNombre(nombre.getText().toString()); lugar.setTipo(TipoLugar.values()[tipo.getSelectedItemPosition()]); lugar.setDireccion(direccion.getText().toString()); lugar.setTelefono(Integer.parseInt(telefono.getText().toString())); lugar.setUrl(url.getText().toString()); lugar.setComentario(comentario.getText().toString()); finish(); Ejecuta la aplicación. Modifica algún lugar y pulsa en Guardar. Al regresar a la actividad anterior los valores permanecen sin variación. Sin embargo si pulsas la tecla volver y entras a visualizar el mismo lugar, los cambios sí que son actualizados. ¿Qué puede estar pasando? Ejercicio paso a paso: Refrescar valores en VistaLugar tras entrar en EdicionLugar Parece que al regresar a VistaLugar desde EdicionLugar no estamos indicando que vuelva a obtener los datos mostrados en las vistas. Para modificar estos valores puedes tratar de hacer los siguientes pasos: 1. En VistaLugar crea el método actualizarVistas() y mueve a este método en el código deonCreate() que inicializa los valores de la vistas. Es decir desde TextView nombre =… hasta el final del método. 2. En el método onCreate() realiza una llamada a este método. 3. En el método onOptionsItemSelected() reemplaza startActivity(intent) porstartActivityForResult(intent, 1234). 4. Añade el siguiene método: @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 1234) { actualizarVistas(); findViewById(R.id.scrollView1).invalidate(); } } Una vez regresamos de la actividad EdicionLugar lo que hacemos es actualizar los valores de las vistas y forzar al sistema a que repinte la vista con id scrollView1. Esta vista corresponde al ScrollViewque contiene todo el layout.
  • 84. Añadiendo una lista de puntuaciones en Asteroides Muchos videojuegos permiten recordar las puntuaciones de partidas anteriores, de esta forma, un jugador puede tratar de superar su propio récord o mejorar el de otros jugadores. En el capítulo 9 estudiaremos varios métodos para que esta información se almacene permanentemente en el sistema. En el capítulo 10 estudiaremos como podemos compartirlo utilizando Internet. En este capítulo nos centraremos en representar esta lista de puntuaciones de forma atractiva utilizando la vista ListView. Vamos a intentar que el mecanismo de acceso a esta lista de puntuaciones sea lo más independiente posible del método final escogido. Con este propósito, vamos a definir la interfaz AlmacenPuntuaciones. Ejercicio paso a paso: El interfaz AlmacenPuntuaciones 1. Abre la aplicación Asteroides. 2. Pulsa con el botón derecho sobre la carpeta de código (src/org.example.asteroides) y selecciona New > Interface. 3. En el campo Name: introduce AlmacenPuntuaciones y pulsa Finish. 4. Introduce el código que se muestra a continuación: public interface AlmacenPuntuaciones { public void guardarPuntuacion(int puntos,String nombre,long fecha); public Vector<String> listaPuntuaciones(int cantidad); } Nota sobre Java: La interfaz es una clase abstracta pura, es decir una clase donde se indican los métodos pero no se implementa ninguno (en este caso se dice que los métodos son abstractos). Permite al programador de la clase establecer la estructura de esta (nombres de métodos, sus parámetros y tipos que retorna, pero no el código de cada método). Una interfaz también puede contener constantes, es decir campos de tipo staticy final. Las diferentes clases que definamos para almacenar puntuaciones han de implementar esta interfaz. Como ves tiene dos métodos. El primero para guardar la puntuación de una partida, con los parámetros puntuación obtenida, nombre del jugador y fecha de la partida. La segunda es para obtener una lista de puntuaciones previamente almacenadas. El parámetro cantidad indica el número máximo de puntuaciones que ha de devolver. 5. Veamos a continuación una clase que utiliza esta interfaz. Para ello crea en el proyecto la claseAlmacenPuntuacionesArray. 6. Introduce el siguiente código: public class AlmacenPuntuacionesArray implements AlmacenPuntuaciones{
  • 85. private Vector<String> puntuaciones; public AlmacenPuntuacionesArray() { puntuaciones= newVector<String>(); puntuaciones.add("123000 Pepito Domingez"); puntuaciones.add("111000 Pedro Martinez"); puntuaciones.add("011000 Paco Pérez"); } public void guardarPuntuacion(int puntos, String nombre, long fecha) { puntuaciones.add(0, puntos + " "+ nombre); } public Vector<String> listaPuntuaciones(int cantidad) { return puntuaciones; } } Esta clase almacena la lista de puntuaciones en un vector de String. Tiene el inconveniente de que al tratarse de una variable local, cada vez que se cierre la aplicación se perderán las puntuaciones. El constructor inicializa el array e introduce tres valores. La idea es que aunque todavía no esté programado el juego y no podamos jugar, tengamos ya algunas puntuaciones para poder representar una lista. El método guardarPuntuacion() se limita a insertar en la primera posición del array un String con los puntos y el nombre. La fecha no es almacenada. El método listaPuntuaciones() devuelve el vector de String entero, sin tener en cuenta el parámetro cantidad que debería limitar el número de Strings devueltos. 7. En la actividad Asteroides tendrás que declarar una variable para almacenar las puntuaciones: public static AlmacenPuntuaciones almacen= new AlmacenPuntuacionesA rray(); Nota sobre Java:El modificador static permite compartir el valor de una variable entre todos los objetos de la clase. Es decir, aunque se creen varios objetos, solo existirá una única variable almacen compartida por todos los objetos. El modificador public permite acceder a la variable desde fuera de la clase. Por lo tanto, no será necesario crear métodos getters y setters. Para acceder a esta variable no tendremos más que escribir el nombre de la clase seguida de un punto y el nombre de la variable. Es decir Asteroides.almacen.
  • 86. 8. Para que los jugadores puedan ver las últimas puntuaciones obtenidas, modifica el cuarto botón dellayout main.xml para que en lugar del texto “Salir” se visualice “Puntuaciones”. Para ello modifica los ficheros res/values/strings. También sería interesante que cambiaras el fichero res/values-en/strings. 9. Modifica el escuchador asociado al cuarto botón para que llame al método: public void lanzarPuntuaciones(View view) { Intent i = new Intent(this, Puntuaciones.class); startActivity(i); } 10. De momento no te permitirá ejecutar la aplicación. Hasta que en el siguiente apartado no creemos la actividad Puntuaciones no será posible. {jcomments on} La vista ListView Una vista ListView visualiza una lista deslizable verticalmente de varios elementos, donde cada elemento puede definirse como un Layout .Su utilización es algo compleja, pero muy potente. Un ejemplo lo podemos ver en la siguiente figura: Definir un ListView conlleva los siguientes cuatro pasos:  Diseñar un Layout que lo contenga al ListView  Diseñar un Layout individual que se repetirá en la lista  Implementar una actividad que lo visualice el Layout con el ListView  Personalizar cada una de los Layouts individuales según nuestros datos Veamos estos pasos con más detalle: Para utilizar un ListView dentro de un Layout puedes de usar la siguiente estructura: <FrameLayout> <ListView android:id="@android:id/list"... /> <TextView android:id="@android:id/empty" ... /> </FrameLayout>
  • 87. Donde tenemos un FrameLayout que permite visualizar dos posibles elementos, uno u otro, pero no los dos simultáneamente. El primero es el ListView que se visualizará cuando haya algún elemento en la lista. El segundo puede ser cualquier tipo de vista y se visualizará cuando no existan elementos en la lista. El sistema controla la visibilidad de forma automática, solo has de tener cuidado de identificar cada uno de los elementos con el valor exacto que se muestra. NOTA: Recuerda que para crear nuevos identificadores debes utilizar la expresión"@+id/nombre_identificador". El carácter @ significa que se trata de un identificador de recurso que se definirá en la clase R.java. El carácter + significa que el recurso ha de ser creado en este momento. En este caso hemos utilizado identificadores definidos en el sistema (es decir @android:significa que es un recurso definido en la clase android.R.java). Una vez creado el Layout que contiene el ListView tendremos que visualizarlo en una actividad. Para este propósito utilizaremos un tipo de actividad especial, ListActivity. También tendremos que indicar al sistema cada uno de los Layouts individuales que contendrá el ListView. Esto lo haremos llamando al método setListAdapter(). Existen varias alternativas con diferentes grados de dificultad. Para una mejor conprensión iremos mostrando tres ejemplos de uso de setListAdapter(), de más sencillo a más complejo. Las capturas anteriores muestran los tres ListView que vamos construir. El de la izquierda se limita a mostrar una lista de Strings. El del centro visualiza una lista de un Layout diseñado por nosotros. Aunque este Layout tiene varios componentes (una imagen y dos textos), solo cambiamos uno de los textos. En el último ejemplo cambiaremos también la imagen de cada elemento. video[Tutorial] Uso de ListView Un ListView que visualiza una lista de Strings
  • 88. Ejercicio paso a paso: Un ListView que visualiza una lista de Strings 1. El Layout que utilizaremos en Asteroides para mostrar las puntuaciones se llamará puntuaciones.xml. En el se incluye una vista ListView. Crea el Layout con el siguiente código: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Puntuaciones" android:gravity="center" android:layout_margin="10px" android:textSize="10pt"/> <FrameLayout android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false" /> <TextView android:id="@android:id/empty" android:layout_width="match_parent" android:layout_height="match_parent" android:text="No hay puntuaciones" /> </FrameLayout> </LinearLayout> 2. Necesitamos ahora crear la actividad Puntuaciones para visualizar el Layout anterior. Crea una nueva clase en tu proyecto e introduce el siguiente código: public class Puntuaciones extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.puntuaciones); setListAdapter(newArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Asteroides.almacen.listaPuntuaciones(10))); } } Toda actividad que vaya a visualizar un ListView ha de heredar de ListActivity. Además, ha de llamar al método setListAdapter() para indicar el adaptadorcon la lista de elementos a visualizar. En el ejemplo se ha utilizado una de la posibilidades más sencillas, para crear un adaptador,usar la clase ArrayAdapter<clase>.
  • 89. Un ArrayAdapter crea las vistas delListView a partir de los datos almacenados en un array.Puedes utilizar un array que contenga datos de cualquier clase, no tienes más que indicar en <Clase> la clase deseada. En este caso se utiliza de un array de String[1]. El constructorde ArrayAdapter<clase> tiene tres parámetros: El primer parámetro es un Context con información sobre el entorno de la aplicación. Utilizaremos como contexto la misma actividad que hace la llamada. El segundo parámetro es un Layout, utilizado para representar cada elemento de la lista. En este ejemplo, en lugar de definir uno nuevo,utilizaremos una ya definido en el sistema. El último parámetro es un array con los strings a mostrar. Para ello, llamamos al método listaPuntuaciones() que nos devuelve esta lista del objeto estático almacen de la clase Asteroides. 3. Recuerda que toda nueva actividad ha de ser registrada en AndroidManifest.xml. 4. Prueba si funcionan las modificaciones introducidas. Un ListView que visualiza Layouts personalizados Vamos a personalizar el ListView anterior para que cada elemento de la lista sea un Layoutdefinido por nosotros. Para ello sigue los siguientes pasos: Ejercicio paso a paso: Un ListView que visualiza layouts personalizados 1. Reemplaza la clase anterior por: public class Puntuaciones extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.puntuaciones); setListAdapter( new ArrayAdapter<String>(this, R.layout.elemento_lista, R.id.titulo, Asteroides.almacen.listaPuntuaciones(10))); } } Como hemos explicado, la clase ArrayAdapter<String> permite insertar los datos desde un array de String en nuestro ListView. En este ejemplo se utiliza un constructor con cuatro parámetros: R.layout.elemento_lista: es una referencia de recurso a la vista que será utilizada repetidas veces para formar la lista. Se define a continuación. R.id.titulo: identifica un id de la vista anterior que ha de ser un TextView. Su texto será reemplazado por el que se indica en el siguiente parámetro. Asteroides.almacen.listaPuntuaciones(10): vector de String con los textos que serán visualizados en cada uno de los TextView. Esta lista es obtenida accediendo a la claseAsteroides a su variable estática almacen llamando a su método listaPuntuaciones().
  • 90. 2. Ahora hemos de definir el Layout que representará cada uno de los elementos de la lista. Crea el fichero res/Layout/elemento_lista.xml con el siguiente código: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight"> <ImageView android:id="@+id/icono" android:layout_width="?android:attr/listPreferredItemHeight" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:src="@drawable/asteroide2"/> <TextView android:id="@+id/titulo" android:layout_width="matchl_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/icono" android:layout_alignParentTop="true" android:textAppearance="?android:attr/textAppearanceLarge" android:singleLine="true" /> <TextView android:id="@+id/subtitulo" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Otro Texto" android:layout_toRightOf="@id/icono" android:layout_below="@id/titulo" android:layout_alignParentBottom="true" android:gravity="center"/> </RelativeLayout> Este Layout representa una imagen a la izquierda con dos textos a la derecha, uno de mayor tamaño en la parte superior. Para combinar estos elementos se ha escogido un RelativeLayout, donde el alto se establece a partir de un parámetro de configuración del sistema ?android:attr/listPreferredItemHeight. El primer elemento que contiene es un ImageView alineado a la izquierda. Su alto es la misma que el contenedor (match_parent) mientras que el ancho se establece con el mismo parámetro que el alto del contenedor.Por lo tanto la imagen será cuadrada. 3. Las imágenes utilizadas en la aplicación Asteroides puedes descargarlas de www.androidcurso.com. En el menú El gran libro de Android / Ficheros usados en ejercicios dentro de Graficos.zip. Copia el fichero asteriode1.png, asteriode2.png y asteriode3.png a la carpeta res/drawable. 4. Ejecuta la aplicación y verifica el resultado. Un ListView con nuestro propio adaptador En el ejercicio anterior hemos visto como podíamos asociar un Layout definido por nosotros alListView y personalizar uno de sus campos. Si queremos algo más adaptable,por ejemplo cambiar varios campos, tendremos que escribir nuestro propio adaptador extendiendo la clase BaseAdapter. En esta clase habrá que sobreescribir los siguientes cuatro métodos: View getView(int position, View convertView, ViewGroup parent) Este método ha de construir un nuevo objeto View que será visualizado en la posición position . Opcionalmente podemos partir de una vista base convertView para generar más rápido este objeto. El último parámetro corresponde al contenedor de vistas donde el objeto va a ser añadido. int getCount() Devuelve el número de elementos de la lista. Object getItem(int position) Devuelve el elemento en una determinada posición de la lista.
  • 91. long getItemId(int position) Devuelve el identificador de fila de una determinada posición de la lista. Veamos un ejemplo: Ejercicio paso a paso: Un ListView con nuestro propio adaptador 1. Crea la clase MiAdaptador.java en el proyecto con el siguiente código: public class MiAdaptador extends BaseAdapter { privatefinal Activity actividad; privatefinal Vector<String> lista; public MiAdaptador(Activity actividad, Vector<String> lista) { super(); this.actividad = actividad; this.lista= lista; } public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = actividad.getLayoutInflater(); View view = inflater.inflate(R.layout.elemento_lista, null, true); true); TextView textView =(TextView)view.findViewById(R.id.titulo); textView.setText(lista.elementAt(position)); ImageView imageView=(ImageView)view.findViewById(R.id.icono); switch (Math.round((float)Math.random()*3)){ case 0: imageView.setImageResource(R.drawable.asteroide1); break; case 1: imageView.setImageResource(R.drawable.asteroide2); break; default: imageView.setImageResource(R.drawable.asteroide3); break; } return view; } public int getCount() { return lista.size();
  • 92. } public Object getItem(int arg0) { return lista.elementAt(arg0); } public long getItemId(int position) { return position; } } 2. En el constructor de la clase se indica la actividad donde se ejecutará y la lista de datos a visualizar. El método más importante de esta clase es getView() el cual tiene que construir los diferentes Layouts que serán añadidos en la lista. Comenzamos construyendo un objeto View a partir del código xml definido enelemento_lista.xml. Este trabajo se realiza por medio de la clase LayoutInflater.Luego, se modifica el texto de uno de los TextView según el array que se pasó en el constructor. Finalmente, se obtiene un número al azar (Math.round()) y se asigna uno de los tres gráficos de forma aleatoria. 3. Reemplaza en la clase Puntuaciones la llamada al constructor de ArrayAdapter<String> por: setListAdapter(new MiAdaptador(this, Asteroides.almacen.listaPuntuaciones(10))); 4. Ejecuta la aplicacióny verifica el resultado. NOTA: En algunos casos el adaptador ha de trabajar con listas muy grandes o estas listas han de ser creadas desde un servidor. En estos casos es mejor ir solicitando la información a medida que se va representando. Un ejemplo se muestra en la aplicación ApiDemos descrita en el capítulo 1, en la actividad: com.example.android.apis.view.List13 Detectar una pulsación sobre un elemento de la lista Un ListView puede tener diferentes componentes que nos permitan interaccionar con el usuario. Por ejemplo, cada elemento definido en getView() puede tener botones para diferentes acciones. Hay un tipo de interacción muy sencilla de definir. La clase ListActivity tiene un método que es invocado cada vez que se pulsa sobre un elemento de la lista. El siguiente ejercicio ilustra cómo utilizarlo.
  • 93. Ejercicio paso a paso: Detectar una pulsación sobre un elemento de la lista 1. Añade el siguiente método a la clase Puntuaciones.java: @Override protected void onListItemClick(ListView listView, View view, int position, long id) { super.onListItemClick(listView, view, position, id); Object o = getListAdapter().getItem(position); Toast.makeText(this, "Selección: " + Integer.toString(position) + " - " + o.toString(),Toast.LENGTH_LONG).show(); } 2. Ejecuta la aplicación, pulsa en “Puntuaciones” y luego en una puntuaciób para verificarel resultado. Las intenciones Una intención representa la voluntad de realizar alguna acción o tarea; como realizar una llamada de teléfono o visualizar una página web. Una intención nos permite lanzar una actividad o servicio de nuestra aplicación o de una aplicación diferente. video[Tutorial] Las intenciones en Android Existen dos tipos de intenciones:  Intenciones explícitas: se indica exactamente el componente a lanzar. Su utilización típica es la de ir ejecutando los diferentes componentes internos de una aplicación. Por ejemplo, desde la actividadAsteroides lanzamos AcercaDe por medio de una intención explicita.  Intenciones implícitas: pueden solicitar tareas abstractas, como “quiero tomar una foto” o “quiero enviar un mensaje”. Además las intenciones se resuelven en tiempo de ejecución, de forma que el sistema mirará cuantos compomentes han registrado la posibilidad de ejecutar ese tipo deintención. Si encuentra varias el sistema puede preguntar al usuario el comomente que prefiere utilizar.
  • 94. Además, como se ha estudiado en el apartado Comunicación entre actividades las intenciones ofrecen un servicio de paso de mensajes que permite interconectar datos entre componentes. En concreto se utilizan intenciones cada vez que queramos:  lanzar una actividad (startActivity() y startActivityForResult())  lanzar un servicio (startService())  lanzar un anuncio de tipo broadcast (sendBroadcast())  conectarnos con un servicio (bindService()) En muchas ocasiones una intención no será inicializada por la aplicación, si no por el sistema, por ejemplo, cuando pedimos visualizar una página Web. En otras ocasiones será necesario que la aplicación inicialice su propia intención. Para ello se creará un objeto de la clase Intent. Cuando se crea una Intención (es decir, se instancia un objeto de tipo Intent) esta contiene información de interés para que el sistema trate adecuadamente la intención o para el componente que recibe la intención. Puede incluir la siguiente información: Nombre del componente: Identificamos el componente que queremos lanzar con la intención. Podemos utilizar el nombre de clase totalmente cualificado (org.example.asteroides.AcercaDe) que queremos lanzar. El nombre del componente es opcional. En caso de no indicarse se utilizará otra información de la intención para obtener el componente a lanzar. A este tipo de intenciones se les conocía como intenciones explícitas. Acción: Una cadena de caracteres donde indicamos la acción a realizar (o en caso de un Receptor de anuncios (Broadcast receiver)la acción que tuvo lugar y queremos reportar). La clase Intent define una serie de constantes para acciones genéricas que son listadas a continuación. No obstante, además de estas podemos definir nuevas acciones: Constante componente a lanzar Acción ACTION_CALL Actividad Inicializa una llamada de teléfono. ACTION_EDIT Actividad Visualiza datos paraque el usuario los edite. ACTION_MAIN Actividad Arranca como actividad principal de una tarea (sin datos de entrada y sin devolver datos) ACTION_SYNC Actividad Sincroniza datos en un servidor con los datos un dispositivo móvil. ACTION_BATTERY_LOW receptor de anuncios Advertencia de bateria baja. ACTION_HEADSET_PLUG receptor de anuncios Los auriculares han sido conectados o desconectados. ACTION_SCREEN_ON receptor de anuncios La pantalla es activada. ACTION_TIMEZONE_CHANGED receptor de anuncios Se cambia la selección de zona horaria. Tabla 3: Algunas acciones estándar de las Intenciones
  • 95. También puedes definir tus propias acciones. En este caso has de indicar el paquete de tu aplicación como prefijo. Por ejemplo: org.example.asteroides.MUESTRA_PUNTUACIONES. Categoría: Complementa a la acción. Indica información adicional sobre el tipo de componente que ha de ser lanzado. El número de categorías puede ser arbitrariamente ampliado. No obstante, en la clase Intent se definen una serie de categorías genéricas que podemos utilizar. Constante Significado CATEGORY_BROWSABLE La actividad lanzada puede ser con seguridad invocada por el navegador para mostrar los datos referenciados por un enlace - por ejemplo, una imagen o un mensaje de correo electrónico. CATEGORY_HOME La actividad muestra la pantalla de inicio,la primera pantalla que ve el usuario cuando el dispositivo está encendido o cuando la tecla HOME es presionada. CATEGORY_LAUNCHER La actividad puede ser la actividad inicial de una tarea y se muestra en el lanzador de aplicaciones de nivel superior. CATEGORY_PREFERENCE La actividad a lanzar es un panel de preferencias. Tabla 4: Categorías estándar de las Intenciones Una categoría suele utilizarse junto con una acción para aportar información adicional. Por ejemplo, indicaremos ACTION_MAIN a las actividades que pueden utilizarse como puntos de entrada de una aplicación. Indicaremos además CATEGORY_LAUNCHER para que la actividad sea mostrada en la pantalla de inicio. Datos: Referencia a los datos con los que trabajaremos. Hay que expresar estos datos por medio de una URI (el mismo concepto ampliamente utilizado en Internet). Ejemplos de URIs son: tel:963228525,http://www.androidcurso.com, content://call_log/calls… En muchos casos resulta importante saber el tipo de datos con el que se trabaja. Con este propósito se indica el tipo MIME asociado a la URI, es decir, se utiliza el mismo mecanismo que en Internet. Ejemplos de tipos MIME son text/xml, image/jpeg, audio/mp3… Extras: Información adicional que será recibida por el componente lanzado. Está formada por un conjunto de pares variable/valor. Estas colecciones de valores se almacenan en un objeto de la clase Bundle. Su utilización ha sido descrita en la sección Comunicación entre actividades. Recordemos cómo se introducían estos valores en un Intent. intent.putExtra("usuario", "Pepito Perez"); intent.putExtra("edad", 27); En el apartado Creación de nuevas actividades aprendimos a lanzar una actividad de forma explícita utilizando el constructor Intent(Context contexto, Class<?> clase). Por ejemplo, para lanzar la actividad AcercaDeescribíamos: Intent intent = new Intent(this, AcercaDe.class); startActivity(intent);
  • 96. Para lanzar una actividad de forma implícita podemos usar el constructor Intent(String action, Uri uri). Por ejemplo: Intent intent = new Intent(Intent.ACTION_DIAL, URI.parse("tel:962849347"); startActivity(intent); También se puede utilizar startActivityForResult() si esperamos que la actividad nos devuelva datos. Ejercicio paso a paso: Uso de intenciones implícitas 1. Crea un nuevo proyecto con nombre Intenciones. 2. El Layout de la actividad inicial ha de estarformado por cinco botones,taly como se muestra a continuación: 3. Abre la actividad principal e incorpora los siguientes métodos:
  • 97. public void pgWeb(View view) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.androidcurso.com/")); startActivity(intent); } public void llamadaTelefono(View view) { Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:962849347")); startActivity(intent); } public void googleMaps(View view) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:41.656313,-0.877351")); startActivity(intent); } public void tomarFoto(View view) { Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); startActivity(intent); } public void mandarCorreo(View view) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, "asunto"); intent.putExtra(Intent.EXTRA_TEXT, "texto del correo"); intent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jtomas@upv.es" }); startActivity(intent); } . 4. Asocia el atributo onClick de cada uno de los botones al método correspondiente. 5. Abre AndroidManifest.xml e inserta la siguiente línea al final, antes de </manifest>: <uses-permission android:name="android.permission.CALL_PHONE"/> NOTA: En el CAPÍTULO 7 se estudiará el tema de la seguridad.Aprenderás como has de solicitar el permiso adecuado si quieres que tu aplicación llame por teléfono o acceda a Internet.Cuando estas acciones no las realizas directamente, si no que las pides a través de una intención,no es tu aplicación quien las realiza y por tanto no has de pedir estos permisos. La única excepción es el caso de realizar una llamada de teléfono.Para poder realiza una llamada de teléfono desde una intención si que hay que pedir el permiso correspondiente. 6. Si ejecutas esta aplicación en un emulador es muy posible que el botón mandar Correo o Google Maps no funcione. La razón es que no hay ninguna aplicación instalada en el emulador que sea capaz de realizar este tipo de acciones. Si tienes estos problemas, Abre el AVD Manager y crea un dispositivo virtual con Google API. Estos dispositivos incorporan además de las API de Android, algunas de las API de Google, como la de Google Maps (Estas API se estudiarán más adelante). 7. Ejecuta la aplicación en un terminal real. Observa como el botón mandar Correo te permite seleccionar entre diferentes aplicaciones con esta funcionalidad.
  • 98. 8. Este resultado puede variar en función de las aplicaciones instaladas.
  • 99. Recursos adicionales: Tabla con intenciones que podemos utilizar de aplicaciones Google Aplicación URI Acción Resultado Navegador Web http://dirección_web https://dirección_web VIEW Abre una ventana de navegador con una URL. "" (cadena vacía) http://dirección_web https://dirección_web WEB_SEARCH Abre el fichero en la ubicación indicada en el navegador. Teléfono tel:número_teléfono CALL Realiza una llamada de teléfono. Los números validos se definen enIETF RFC 3966 . Ejem.tel:2125551212.. Necesitamos el permiso android.permission.CALL_PHONE tel:número_teléfono voicemail: DIAL Introduce un número en la aplicación Teléfono, sin llegar a realizar la llamada. No necesita permiso. Google Maps geo:latitud,longitud geo:lat,long?z=zoom geo:0,0?q=dirección geo:0,0?q=búsqueda VIEW Abre la aplicación Google Maps para una localización determinada. El campo z específica el nivel de zoom. Google Streetview google.streetview: cbll=latitud,longitud& cbp=1,yaw,,pitch,zoom& mz=mapZoom VIEW Abre la aplicación Street View para la ubicación dada. El esquema de URI se basa en la sintaxis que utiliza Google Maps. Solo el campo cbll es obligatorio. Práctica: Uso de intenciones implícitas
  • 100. 1. Crea nuevos botones en la aplicación del ejercicio anterior y experimenta con otro tipo de acciones y URls. Puedes consultar la tabla anterior. A continuación tienes algunas propuestas: 2. Compara las acciones VIEW y WEB_SEARCH. ¿Encuentras alguna diferencia? 3. Compara las acciones CALL y DIAL. ¿Encuentras alguna diferencia? 4. Experimenta con Google Streetview La etiqueta <intent-filter> Cuando creamos una nueva actividades, servicios o receptor broadcast podemos informar al sistema que tipo de intenciones implícitas pueden ser resultas con nuestro componente. Para conseguir esto utilizaremos la etiqueta<intent-filter> de AndroidManifest.xml. Cuando desarrollamos una aplicación lo habitual es utilizar intenciones explicitas, que son resueltas utilizando el nombre de la clase. Por lo tanto, si vamos a llamar a nuestro componente de forma explicita, no tiene sentido crear un filtro de intenciones.