Beruflich Dokumente
Kultur Dokumente
TEMA
2.
TEMA
Desarrollo de cdigo
1.1. Herramientas y fases de construccin
En el tema 1 ya se describi el entorno de desarrollo para Android as como el proceso de desarrollo de una aplicacin. Lo primero que vamos a realizar es verificar la correcta configuracin de nuestro entorno y para ello vamos a aadir a nuestro entorno Eclipse un ejemplo de aplicacin proporcionado en el SDK y lo ejecutaremos, pero antes vamos a describir primeramente las fases de construccin de una aplicacin Android.
Android file
AndroidManifest.xml project.properties src Folder scr/com/example/app1_android/ App1_Android.java res Folder res/drawable/ res/anim res/color res/layout res/menu
Descripcin
Descripcin del contenido de la Aplicacin. Se genera automticamente con la creacin de un proyecto. Define el destino de la aplicacin y otras opciones requeridas por el sistema. Carpeta en la que reside el cdigo fuente de la aplicacin. Archivo del cdigo fuente que define el punto de entrada de la aplicacin Android. Carpeta donde se manejan todos los recursos de la aplicacin. Iconos de la aplicacin. Animaciones. Definicin de colores. Definicin de ventanas. Definicin de mens.
2.
Cualquier recurso el cual se identifica mediante el valor de una etiqueta. Libreras privadas. Archivo de la apariencia de la pantalla. Recursos de la aplicacin.
1. 2. 3. 4. 5. 6. 7.
Seleccionar el icono Ejecutar como (Run As) desde la barra de herramientas. Seleccionar App1_Android_RunConfiguration en el men desplegable. Seleccionar la instancia del emulador deseado. Seleccionamos el AVD en el que deseamos probar nuestra aplicacin. Comprobar la correcta ejecucin de nuestra aplicacin en el emulador. Hacemos clic en el botn Men para desbloquear el men y dar paso a la ejecucin de la aplicacin. Pulsar Home en el emulador para terminar la ejecucin de la aplicacin.
Android Project
2.
2.
Despus de crear un proyecto Android debe quedarnos las siguientes pantallas con los nombres de Proyectos acorde a los que haya puesto cada uno, pero de manera genrica sera un esquema parecido al siguiente (Android 4.0):
2.
Actividad
Antes de empezar con los elementos necesarios para la programacin, veamos unos conceptos relacionados bsicos. Para empezar, diremos que una actividad es un componente de la aplicacin ANDROID que proporciona interaccin con el usuario. Podemos interpretarlo como la tradicional ventana con la que se trabaja. Una tarea simple ANDROID la considera como una actividad. A semejanza de la programacin visual para PC, en la que tenamos una ventana de la que dependan varias ventanas hijas, en ANDROID cada una de estas se considera una actividad. Las actividades pueden comunicarse datos entre ellas y lanzarse las unas a las otras. Entendemos tambin el concepto actividad padre y actividad hija. De hecho, cuando una actividad (padre) lanza a otra (hija), la actividad padre se detiene y deja de ejecutarse mantenindose en ese estado hasta que la actividad hija concluya. Las actividades se terminan porque se concluyen mediante cdigo o bien porque se pulsa el botn de regreso del dispositivo. Todas las actividades estn informadas en todo momento de lo que est pasando, la situacin en la que se encuentra y de esta manera pueden tomar acciones antes de que llegue a un determinado punto. A esto se le denomina el Ciclo de Vida de una Actividad. - Actividad: Se puede asemejar a una ventana de la programacin normal que puede ocupar todo el espacio de la pantalla o no. Es una tarea simple que va a realizar el usuario. - Aplicacin: Consta de una serie de actividades que se ubican en una pila y se retiran de la misma al finalizar bien mediante el mtodo finish() o al pulsar el botn BACK. El cambio de estado de una actividad se le notifica mediante callbacks (ciclo de vida) o eventos.
2.
Si hay varias actividades definidas para un tipo de Intent se le preguntar al usuario cul se tiene que lanzar.
Evento
onCreate onRestart onStart onResume onPause onStop onDestroy
Se produce
Al crearse, se usa para establecer el layout y recursos importantes. Despus de ser parada y antes de ser reiniciada. Justo antes de ser visible. Justo antes de interactuar con el usuario. Cuando se va a lanzar otra actividad y sta deja de tener el foco. Ya no es visible. Al terminar la actividad por llamar a la funcin finish() o por el sistema (falta de memoria, cambio de orientacin, etc) de forma automtica.
Los ltimos 3 mtodos los puede finalizar el sistema en cualquier momento, incluso antes de terminar sus propia ejecucin. De estos 3 ltimos, solo onPause se nos asegura por parte del sistema que ser llamado siempre en el ciclo de vida pero nunca es seguro que termine su ejecucin. En la siguiente hoja tenemos el Ciclo de Vida de una Actividad.
2.
Actividad
Vamos a crear una aplicacin en la que se mantendr una lista de libros y se recordar el que tenamos seleccionado antes de ver el detalle, que se abrir en otra actividad al pinchar sobre un libro.
main.xml
<?xml version="1.0" encoding="utf-8"?> <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/lblLibros" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Lista de Libros"/> <ListView android:id="@+id/lstLibros" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout>
2.
details.xml
<?xml version="1.0" encoding="utf-8"?> <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/txtNombre" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="TextView" /> <TextView android:id="@+id/txtAuthor" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="TextView" /> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/txtVal11" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Valor 1: "/> <EditText android:id="@+id/txtVal1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:inputType="text" android:text="Valor 1 para setExtra" /> </LinearLayout> <LinearLayout android:id="@+id/LinearLayout02" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/liblVal2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Valor 2: " /> <EditText android:id="@+id/txtVal2" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" android:text="Valor 2 para setData" /> </LinearLayout>
2.
Estos dos ficheros que hemos visto, el main.xml y el details.xml son para la disposicin de los controles grficos dentro de las 2 actividades que vamos a crear. La actividad principal es el main y la segunda actividad es el details. Lo siguiente consiste en irnos a la carpeta src donde crearemos un package o paquete con el nombre de paquete que pusimos en la creacin del Proyecto Android. En este caso hemos puesto el nombre Sie7e.examples.com y ese es el nombre de nuestro package que debemos utilizar.
package Sie7e.examples.com; public final class Datos { static public String lista[][] = { {"Libro 1", "Autor 1"}, {"Libro 2", "Autor 2"}, {"Libro 3", "Autor 3"}, {"Libro 4", "Autor 4"}, {"Libro 5", "Autor 5"}, {"Libro 6", "Autor 6"}, {"Libro 7", "Autor 7"}, {"Libro 8", "Autor 8"}, {"Libro 9", "Autor 9"}, }; public static String[] getNombres() { String ret[] = new String[9]; //el compilador optimizar a estos as que mejor as ret[0]=lista[0][0]; ret[1]=lista[1][0]; ret[2]=lista[2][0]; ret[3]=lista[3][0]; ret[4]=lista[4][0]; ret[5]=lista[5][0]; ret[6]=lista[6][0]; ret[7]=lista[7][0]; ret[8]=lista[8][0]; return ret; } }
Es una clase de ayuda para mantener los datos. Ms adelante se utilizarn mtodos ms efectiviso. El mtodo getNombre devuelve el vector con los nombres de los libros.
MainActivity.java
package Sie7e.examples.com; import import import import import import import import import import android.os.Bundle; android.app.Activity; android.content.Context; android.content.Intent; android.view.View; android.widget.AdapterView; android.widget.AdapterView.OnItemClickListener; android.widget.ArrayAdapter; android.widget.ListView; android.widget.Toast;
2.
public class MainActivity extends Activity { static public String KEY_LIST="numlist"; //calve para acceder al parmetro para recrear static public String KEY_RTN_VAL1 = "valor1"; //clave para lo devuelto por la actividad hija private static int COD_RTN_ACT = 0; Context ctx; int numLista = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ctx = this; if (savedInstanceState != null) { //estamos recreando la actividad, hay un Bundle de vuelta numLista = savedInstanceState.getInt(KEY_LIST, 0); } //ponemos los datos en la lista ListView lv = (ListView) this.findViewById(R.id.lstLibros); lv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Datos.getNombres())); lv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub //nos quedamos con el id pulsado para recrear numLista = position; // la posicin es el ndice del array //lanzar la otra actividad desde un intent Intent intent = new Intent(ctx, Details.class); intent.putExtra(KEY_LIST, numLista); //mandamos el nmero del libro a visualizar startActivityForResult(intent, COD_RTN_ACT); //abrimos y esperamos resultado } }); } public void onActivityResult(int requestCode, int resultCode, Intent intent) { if (resultCode == RESULT_OK && requestCode == COD_RTN_ACT) { //cuando vuelva la actividad de forma correcta recogemos los valores y los mostramos StringBuffer sb = new StringBuffer(); sb.append("De vuelta:\n"); sb.append("Valor 1:" + intent.getStringExtra(KEY_RTN_VAL1) + "\n"); sb.append("Valor 2:" + intent.getData().toString()); Toast.makeText(ctx, sb.toString(), Toast.LENGTH_LONG).show(); //mostraoms en pantalla } } public void onSaveInstaceState(Bundle outState) { outState.putInt(KEY_LIST, numLista); // grabamos los datos para crear la actividad } }
Esta actividad mostrar la lista de los libros y almacena la lgica que al pulsar en un elemento se abra otra actividad. Nos quedamos con el cdigo del libro para pasar datos a la actividad y abrirla para respuesta. Lo hacemos en el cdigo en rojo. Igualmente la actividad implementa el mtodo onActivityResult que se llamar cuando la actividad hija termine. El cdigo para ello est en verde. En el requestCode tendremos el cdigo con el que hemos llamado la actividad en el intent, en este caso COD_RTN_ACT. Y en el campo resultCode el resultado que ponga la actividad antes de terminar. Por ltimo, en el campo Intent, tendremos el Intent de vuelta creado por la actividad hija antes de terminar con los datos que nos pase. Para recoger los datos usamos el Intent con el mtodo getTipoExtra(Clave) donde recogemos el valor del tipo (String, Int, etc) que ha puesto la actividad antes de finalizar. (con clave KEY_RTN_VAL1).
10
2.
Con getData() accedemos a los datos que ha establecido la actividad con setData() antes de finalizar.
Details.java
package Sie7e.examples.com; import import import import import import import import import android.app.Activity; android.content.Intent; android.net.Uri; android.os.Bundle; android.view.View; android.view.View.OnClickListener; android.widget.Button; android.widget.EditText; android.widget.TextView;
public class Details extends Activity{ EditText val1; EditText val2; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.details); Intent intent = getIntent(); //cogemos el Intent que ha generado el lanzamiento int numLista = intent.getIntExtra(MainActivity.KEY_LIST, 0); //los datos que nos pasasn. //ponemos los datos en pantalla TextView txt = (TextView) this.findViewById(R.id.txtNombre); txt.setText(Datos.lista[numLista][0]); txt=(TextView)this.findViewById(R.id.txtAuthor); txt.setText(Datos.lista[numLista][1]); val1 = (EditText) this.findViewById(R.id.txtVal1); val2 = (EditText) this.findViewById(R.id.txtVal2); //gestionamos el botn de cerrar y devolver datos Button bt = (Button) this.findViewById(R.id.cmdVolver); bt.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { // TODO Auto-generated method stub Intent intent = new Intent(); //devolvemos cada dato de forma distinta intent.putExtra(MainActivity.KEY_RTN_VAL1, val1.getText().toString()); intent.setData(Uri.parse(val2.getText().toString())); setResult(RESULT_OK, intent); //resultado y datos a devolver finish(); //fin actividad } }); } }
Esta clase lo que hace es mostrar un libro y recoge dos valores a devolver a la actividad padre. La recoleccin de los datos lo hace en el cdigo de fondo amarillo. En el evento clic del botn preparamos los datos de vuelta a la actividad padre y creamos la actividad finish(). Para el paso de datos creamos un Intent y usamos los mtodos necesarios que son PutExtra con una clave y PutData con una Uri. Finalmente ponemos el cdigo de resultado, RESULT_OK, de la actividad. Resaltado en rojo. Y por ltimo, en el directorio principal del proyecto, creamos el archivos AndroidManifest.xml
11
2.
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="Sie7e.examples.com" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:label="@string/app_name" android:name=".Details"> </activity> </application> </manifest>
Fragmentos
Con la aparicin de las tabletas los programadores se enfrentan al nuevo problema del tamao. El espacio fsico aumenta y se puede solucionar aadiendo elementos pero la aplicacin no ser vlido para todo tipo de dispositivos. Para solventar este problema nace el concepto de Fragmentos y posibilita el transporte de la aplicacin a diferentes tipos de dispositivos de distintos tamaos. Un fragmento representa una parte de un todo, la actividad. Se pueden combinar mltiples fragmentos en una actividad para crear una interfaz multipanel. Es factible reutilizar los fragmentos entre actividades para evitar duplicidad de diseo. Un fragmento es similar a una seccin modular de la actividad con su propio ciclo de vida, eventos y que se pueden eliminar o aadir durante la ejecucin (aunque un fragmento no es independiente, depende del ciclo de vida de la actividad). Existen dos mtodos para aadir un fragmento a una actividad existente: 1. En el fichero XML del layout. 2. En ejecucin, aadindolo a un ViewGroup visible. Se debe tener en cuenta que no es necesaria una interfaz grfica para poder ejecutar un fragmento. Esto hace que se una manera de trabajar de forma no visible, invisible. Al disear con fragmentos debemos tener cuidado que su funcionamiento es similar al de las actividades al igual que su ciclo de vida. Cada actividad va a poseer una pila de fragmentos para su gestin. Dicha pila se ir vaciando mediante el cierre por cdigo de fragmentos o pulsando el botn BACK.
12
2.
3.5 Transacciones
La gestin para aadir, remplazar o borrar un fragmento de una actividad en tiempo de ejecucin se tiene que realizar obligatoriamente con transacciones. Simulan las tpicas de SQL, en donde hasta que no se confirman no se realizan los cambios.
13
2.
Para manejar correctamente las transacciones debemos tener en cuenta: - Hay que primero conseguir un objeto FragmentTransaction usando FragmentManager, utilizando los mtodos add, replace, remove y commit. - Para aadir un fragmento a la correspondiente pila hay que uar addToBackStack() necesariamente pues si no se destruir completamente. - Podemos aplicar animaciones aadiendo as efectos visuales al cambio de fragmentos. - Slo se llamar al mtodo commit una vez finalizadas las modificaciones y es obligatorio hacerlo. Adems solo es posible llamar a este mtodo cuando la actividad se encuentre en primer plano. FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); Fragment newFragment = new ExampleFragment(); FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); transaction.commit();
14
2.
public static class Actividad implements OnArticleSelectedListener { @Override public void onArticleSelected(Uri articleUri) { } }
Actividad
Partiendo de la Actividad anterior, vamos a crear una nueva aplicacin con fragmentos. Al pulsar en un libro mostraremos el detalle del mismo en un fragmento.
Recursos
En el diseo de las aplicaciones hay elementos que no van a ser nunca modificados. Textos, imgenes, etc Todos ellos podemos llevarlos a una zona comn para gestionarlos de forma eficaz y sencilla. Los recursos en la mayora de las situaciones se definen en los ficheros XML dentro del directorio /res del proyecto. Vamos a adentrarnos en estos ficheros XML: 1. Se organizan en carpetas dentro del directorio /res pero no se permiten directorios anidados. 2. Para cada recurso que use nuestra aplicacin podemos asignar uno por defecto y por uno o ms recursos segn una caracterstica del dispositivo o estado del mismo. Los recursos por defectos se utilizarn solo cuando no haya otra alternativa. 3. Las alternativas a un recurso por defecto se designarn aadiendo un calificador al final del nombre del directorio.
15
2.
4.3 Reglas
1. 2. 3. 4. 5. 6. Se pueden especificar varios calificadores separados por guiones. El orden de preferencia se muestra en la tabla1. No se pueden anidar directorios. Los nombres de directorios y calificadores no son sensibles a minsculas y maysculas. Slo se puede dar un valor de cada tipo de calificador en el mismo directorio. No se permite valueses-en. (Hay 2 calificadores). Es importante crear un recurso por defecto. El algoritmo de eleccin de recursos es el siguiente: a. El acceso a los recursos se puede hacer desde programacin con la clase [paquete].R.recursotipo.id directamente en las funciones que usen recursos o con la funcin getResources(). b. En los ficheros XML como [paquete:]recursotipo/id. c. Se puede especificar el paquete calificador si hay problemas en la resolucin de un nombre de recurso pero es optativo. d. En los atributos de estilo, un recurso del tema se referencia con ? en vez de la @.
16
2.
Tabla 1. Recursos permitidos en directorios dentro del directorio /res de un proyecto. (http://developers.android.com/guide/topics/resources/providing-resources.html)
Directorio
animator/
Tipo de recurso XML files that define property animations. XML files that define tween animations. (Property animations can also be saved in this directory, but the animator/ directory is preferred for property animations to distinguish between the two types.) XML files that define a state list of colors. See Color State List Resource
anim/
color/
Bitmap files (.png, .9.png, .jpg, .gif) or XML files that are compiled into the following drawable resource subtypes:
drawable/
Bitmap files Nine-Patches (re-sizable bitmaps) State lists Shapes Animation drawables Other drawables
XML files that define a user interface layout. See Layout Resource. XML files that define application menus, such as an Options Menu, Context Menu, or Sub Menu. See Menu Resource.
Arbitrary files to save in their raw form. To open these resources with a raw InputStream, call Resources.openRawResource() with the resource ID, which is R.raw.filename.
raw/
However, if you need access to original file names and file hierarchy, you might consider saving some resources in the assets/ directory (instead of res/raw/). Files in assets/ are not given a resource ID, so you can read them only using AssetManager. XML files that contain simple values, such as strings, integers, and colors. Whereas XML resource files in other res/ subdirectories define a single resource based on the XML filename, files in the values/ directory describe multiple resources. For a file in this directory, each child of the <resources> element defines a single resource. For example, a <string> element creates an R.string resource and a <color> element creates an R.color resource. Because each resource is defined with its own XML element, you can name the file whatever you want and place different resource types in one file. However, for clarity, you might want to place unique resource types in different files. For example, here are some filename conventions for resources you can create in 17
values/
2.
this directory:
arrays.xml for resource arrays (typed arrays). colors.xml for color values dimens.xml for dimension values. strings.xml for string values. styles.xml for styles.
Arbitrary XML files that can be read at runtime by calling Resources.getXML(). Various XML configuration files must be saved here, such as a searchable configuration.
4.5 Internacionalizacin
1. Hay que dotar al sistema de recursos por defecto para aquellas configuraciones que no tratemos. 2. El lenguaje por defecto se situar en /res/values/ficheros.xml que deseemos. 3. Por cada traduccin crearemos un directorio con el calificador del idioma correspondiente (/res/values-en) y copiaremos los ficheros del punto dos. Para cada fichero traduciremos el literal, el identificador no se tocar.
18
2.
4. Es imperativo que la cadena que deseemos traducir, est en el mismo fichero en los diferentes subdirectorios y que el id utilizado sea el mismo, para que el SSOO pueda encontrarla. 5. Acabaremos el recurso con el id. Podremos probar con el emulador el funcionamiento sin ningn problema cambiando el idioma del sistema.
19
2.
ANEXOS
A CONTROLES BSICOS A1. LAYOUTS
LAYOUT Un Layout es un elemento no visual destinado a controlar la distribucin, posicin y dimensiones de los controles que se insertan en su interior. Estos componentes extienden a la clave ViewGroup, como muchos otros componenetes contenedores. Veamos dichos contenedores. FRAMELAYOUT Es el ms simple. Un FrameLayout coloca todos sus controles hijos alineados con su esquina superior izquierda, de forma que cada control quedar oculto por el control siguiente (a menos que tenga transparencia). Por ello, suele utilizarse para mostrar un nico control en su interior, a modo de contenedor ( placeholder) sencillo para un slo elemento sustituible, por ejemplo una imagen. Los componentes incluidos en un FrameLayout podrn establecer sus propiedades android:layout_width y android:layout_height, que podrn tomar los valores fill_parent (para que el control hijo tome la dimensin de su layout contenedor, es decir, la dimensin del contenedor que lo contiene) o wrap_content (para que el control hijo tome la dimensin de su contenido, es decir, la dimensin real que tiene el componente). En el siguiente ejemplo creamos un contenedor y en su interior establecemos un cuadro de texto. Es cdigo para introducir en el XML.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:id="@+id/TxtNombre" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </FrameLayout>
LINEARLAYOUT Este layout apila uno tras otro todos sus elementos hijos de forma horizontal o vertical segn se establezca su propiedad android:orientation. Al igual que en un FrameLayout, los elementos contenidos en un LinearLayout pueden establecer sus propiedades android:layout_width y android:layout_height para determinar sus dimensiones dentro del layout. Pero en el caso de un LinearLayout, tendremos otro parmetro con el que jugar, la propiedad android:layout_weight.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <EditText android:id="@+id/TxtNombre" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <Button android:id="@+id/BtnAceptar" android:layout_width="wrap_content" android:layout_height="fill_parent" /> </LinearLayout>
20
2.
Esta propiedad nos va a permitir dar a los elementos contenidos en el layout unas dimensiones proporcionales entre ellas. Esto es ms dificil de explicar que de comprender con un ejemplo. Si incluimos en un LinearLayout vertical dos cuadros de texto (EditText) y a uno de ellos le establecemos un layout_weight=1 y al otro un layout_weight=2 conseguiremos como efecto que toda la superficie del layout quede ocupada por los dos cuadros de texto y que adems el segundo sea el doble (relacin entre sus propiedades weight) de alto que el primero.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <EditText android:id="@+id/TxtDato1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <EditText android:id="@+id/TxtDato2" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="2" /> </LinearLayout>
As pues, a pesar de la simplicidad aparente de este layout resulta ser lo suficiente verstil como para sernos de utilidad en muchas ocasiones. TABLELAYOUT Un TableLayout permite distribuir sus elementos hijos de forma tabular, definiendo las filas y columnas necesarias, y la posicin de cada componente dentro de la tabla. La estructura de la tabla se define de forma similar a como se hace en HTML, es decir, indicando las filas que compondrn la tabla (objetos TableRow), y dentro de cada fila las columnas necesarias, con la salvedad de que no existe ningn objeto especial para definir una columna (algo as como un TableColumn) sino que directamente insertaremos los controles necesarios dentro del TableRow y cada componente insertado (que puede ser un control sencillo o incluso otro ViewGroup) corresponder a una columna de la tabla. De esta forma, el nmero final de filas de la tabla se corresponder con el nmero de elementos TableRow insertados, y el nmero total de columnas quedar determinado por el nmero de componentes de la fila que ms componentes contenga. Por norma general, el ancho de cada columna se corresponder con el ancho del mayor componente de dicha columna, pero existen una serie de propiedades que nos ayudarn a modificar este comportamiento: android:stretchColumns. Indicar las columnas que pueden expandir para absorver el espacio libre dejado por las dems columnas a la derecha de la pantalla. android:shrinkColumns. Indicar las columnas que se pueden contraer para dejar espacio al resto de columnas que se puedan salir por la derecha de la palntalla. android:collapseColumns. Indicar las columnas de la tabla que se quieren ocultar completamente. Todas estas propiedades del TableLayout pueden recibir una lista de ndices de columnas separados por comas (ejemplo: android:stretchColumns=1,2,3) o un asterisco para indicar que debe aplicar a todas las columnas (ejemplo: android:stretchColumns=*). Otra caracterstica importante es la posibilidad de que una celda determinada pueda ocupar el espacio de varias columnas de la tabla (anlogo al atributo colspan de HTML). Esto se indicar mediante la propiedad android:layout_span del componente concreto que deber tomar dicho espacio. Veamos un ejemplo:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:stretchColumns="1" >
21
2.
<TableRow> <TextView android:text="Celda 1.1" /> <TextView android:text="Celda 1.2" /> </TableRow> <TableRow> <TextView android:text="Celda 2.1" /> <TextView android:text="Celda 2.2" /> </TableRow> <TableRow> <TextView android:text="Celda 3" android:layout_span="2" /> </TableRow> </TableLayout>
RELATIVELAYOUT El ltimo tipo de layout que vamos a ver es el RelativeLayout. Este layout permite especificar la posicin de cada elemento de forma relativa a su elemento padre o a cualquier otro elemento incluido en el propio layout. De esta forma, al incluir un nuevo elemento X podremos indicar por ejemplo que debe colocarse debajo del elemento Y y alineado a la derecha del layout padre. Veamos esto en el ejemplo siguiente:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/TxtNombre" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/BtnAceptar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/TxtNombre" android:layout_alignParentRight="true" /> </RelativeLayout>
En el ejemplo, el botn BtnAceptar se colocar debajo del cuadro de texto TxtNombre (android:layout_below=@id/TxtNombre) y alineado a la derecha del layout padre (android:layout_alignParentRight=true), adems de dejar un margen a su izquierda de 10 pixeles (android:layout_marginLeft=10px). PROPIEDADES DE POSICIONAMIENTO Al igual que estas tres ltimas propiedades, en un RelativeLayout tendremos un sin fn de propiedades para colocar cada control justo donde queramos. A continuacin veremos una serie de propiedades que son aplicables en nuestro archivo de Layouts XML a los controles y nos servirn para definir la posicin que ocupara un control. Las medidas se colocan entre comillas y van acabadas en dp. dp equivale a densidad de pxeles independientes (una unidad abstracta que se basa en la densidad fsica de la pantalla). Estas unidades son relativas a una pantalla de 160 dpi, as que un dp es un pxel en una pantalla de 160 dpi. La proporcin de DP a pxel cambia con la densidad de pantalla, pero no necesariamente en proporcin directa. Nota: El compilador acepta tanto "dip" y "dp". Veamos las principales:
22
2.
Posicin relativa a otro control: android:layout_above. android:layout_below. android:layout_toLeftOf. android:layout_toRightOf. android:layout_alignLeft. android:layout_alignRight. android:layout_alignTop. android:layout_alignBottom. android:layout_alignBaseline.
Posicin relativa al layout padre: android:layout_alignParentLeft. android:layout_alignParentRight. android:layout_alignParentTop. android:layout_alignParentBottom. android:layout_centerHorizontal. android:layout_centerVertical. android:layout_centerInParent.
Opciones de margen (tambin disponibles para el resto de layouts): android:layout_margin. android:layout_marginBottom. android:layout_marginTop. android:layout_marginLeft. android:layout_marginRight.
Opciones de espaciado o padding (tambin disponibles para el resto de layouts): android:padding. android:paddingBottom. android:paddingTop. android:paddingLeft. android:paddingRight.
23
2.
Tenemos que crear la variable de tipo Button, luego ponerla en modo escucha y a continuacin realizar el procedmiento del click para esa escucha. // Declaramos un variable de tipo botn llamado botn1. Button Boton1 = (Button)findViewById(R.id. boton1); // Activamos el modo escucha para recibir el evento onClick al StartListener1. // Si tuviramos otro botn declararamos otro modo de escucha y lo asociaramos. Boton1.setOnClickListener(startListener1); Button Boton2 = (Button)findViewById(R.id. boton2); Boton2.setOnClickListener(startListener2); Ya fuera del evento onCreate situamos el siguiente cdigo: private OnClickListener startListener1 = new OnClickListener() { public void onClick(View v) { Toast.makeText(Main.this,"Has pulsado el botn 1",Toast.LENGTH_SHORT).show(); } }; private OnClickListener startListener2 = new OnClickListener() { public void onClick(View v) { Toast.makeText(Main.this,"Has pulsado el botn 2",Toast.LENGTH_SHORT).show(); } }; Hay que darse cuenta el hecho que activamos dos escuchadores, uno para cada botn y posteriormente 2 procedimientos para tratar cada uno de estos. Podramos realizar una reagrupacin para reutilizar cdigo quedando de la siguiente manera: En el anterior cdigo incorporamos, que ya lo estudiaremos ms adelante, la clase Toast que sirve para mostrar mensajes al usuario. El tiempo que se muestra se define en la constante LENGTH_SHORT o LENGTH_LONG. Para cualquier otro tiempo deseado se debe usar una actividad o un dilogo que ya se estudiar. Para su implementacin en XML, tenemos la propiedad android:text para indicar el texto a mostrar. Adems de esta propiedad podramos utilizar muchas otras como el color de fondo ( android:background), estilo de fuente (android:typeface), color de fuente (android:textcolor) o tamao de fuente (android:textSize). Un ejemplo sera:
<Button android:id="@+id/Boton" android:text="Haz click." android:layout_width="wrap_content" android:layout_height="wrap_content" />
Tambin tenemos los botones ToogleButton e ImageButton. Del botn ToogleButton destacar como propiedades diferentes textOn y textOff cuyo cometido es para poder indicar si est o no pulsado. Evidentemente los 2 estados no pueden estar a la vez activos por lo que se pueden dar las circustancias siguientes: textOn=ON - textOff=OFF textOn=OFF - textOff=ON De esta manera podremos definir 2 mensajes, uno para situacin. En XML, el ejemplo de la situacin de la izquierda es:
<ToggleButton android:id="@+id/Boton2" android:textOn="ON" android:textOff="OFF" android:layout_width="wrap_content"
24
2.
android:layout_height="wrap_content" />
Por otra parte, el ImageButton es un botn que en vez de tener un texto en su interior contendr una imagen. Dicha imagen se definir en la propiedad android:src que se encontrar definida en el archivo XML de la actividad. El XML sera:
<ImageButton android:id="@+id/BtnBoton3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ok" />
Tenemos la propiedad android:src que indica la imagen a utilizar. ETIQUETAS Hay 3 tipos: LARGE, MEDIUM y SMALL segn el tamao que querramos que ya estn predefinidos. Introducimos en nuestro archivo XML una etiqueta modificando el nombre de la misma y su texto a nuestro gusto y a continuacin en el archivo .java que implemente el mtodo en el que vayamos a trabajar introduciremos el siguiente cdigo: // Declaramos una variable TextView asocindola al TextView que hemos definido en // nuestro archivo XML de visualizacin. TextView texto = (TextView)findViewById(R.id.Texto); // A continuacin establecemos el texto que queremos mostrar. texto.setText("Hola Arnaudis"); En XML, tenemos las mismas propiedades que para el Button, como android:text, android:textcolor o android:typeface entre muchas otras.
<TextView android:id="@+id/Etiqueta" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Etiqueta de texto" android:background="#97C245" android:typeface="monospace" />
Actividad
Realizar un proyecto en Android con un botn en la parte inferior y dos etiquetas en la parte superior unidas de tal forma que al pulsar en el botn en la etiqueta izquierda aparezca tu nombre y en la etiqueta derecha aparezcan tus dos apellidos. Introduce otro botn de tal forma que al pinchar en l se borre el texto que haya aparecido. Realizar un proyecto en Android en el que introduzcas las etiquetas y botones necesarios para que muestre en pantalla el enunciado del problema y lo resuelva. El enunciado del problema es: Sumar los nmeros pares del 10 al 39 o bien Sumar los nmeros impares del 17 al 51.
Actividad
A3. IMGENES
IMAGEVIEW El control ImageView permite mostrar imgenes en la aplicacin. La propiedad ms interesante es android:src, que permite indicar la imagen a mostrar. Nuevamente, lo normal ser indicar como origen de la imagen el identificador de un recurso de nuestra carpeta /res/drawable, por ejemplo, android:src=@drawable/unaimagen. Adems de esta propiedad, existen algunas otras tiles en algunas ocasiones como las destinadas a establecer el tamao mximo que puede ocupar la imagen, android:maxWidth y android:maxHeight.
<ImageView android:id="@+id/Imagen" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/Foto" />
25
2.
En la lgica de la aplicacin, podramos establecer la imagen mediante el mtodo setImageResorce(), pasndole el ID del recurso a utilizar como contenido de la imagen.
ImageView img= (ImageView)findViewById(R.id.Imagen); img.setImageResource(R.drawable.Foto);
Actividad
Realizar una aplicacin en Android en la que colocars una imagen y un botn. Al pulsar en el botn se har visible o invisible dependiendo de si est invisible o visible. Utiliza la propiedad de la imagen android:visibility.
De igual forma, desde nuestro cdigo podremos recuperar y establecer este texto mediante los mtodos getText() y setText(nuevoTexto) respectivamente:
final EditText txtTexto = (EditText)findViewById(R.id.TxtTexto); String texto = txtTexto.getText().toString(); txtTexto.setText("Hola mundo!");
Un detalle que puede haber pasado desapercibido. Os habis fijado en que hemos tenido que hacer un toString() sobre el resultado de getText()? La explicacin para esto es que el mtodo getText() no devuelve un String sino un objeto de tipo Editable, que a su vez implementa la interfaz Spannable. Y esto nos lleva a la caracterstica ms interesante del control EditText, y es que no slo nos permite editar texto plano sino tambin texto enriquecido o con formato. Veamos cmo y qu opciones tenemos, y para empezar comentemos algunas cosas sobre los objetos Spannable. INTERFAZ SPANNED Un objeto de tipo Spanned es algo as como una cadena de caracteres (deriva de la interfaz CharSequence) en la que podemos insertar otros objetos a modo de marcas o etiquetas ( spans) asociados a rangos de caracteres. De esta interfaz deriva la interfaz Spannable, que permite la modificacin de estas marcas, y a su vez de sta ltima deriva la interfaz Editable, que permite adems la modificacin del texto. Aunque en el apartado en el que nos encontramos nos interesaremos principalmente por las marcas de formato de texto, en principio podramos insertar cualquier tipo de objeto. Existen muchos tipos de spans predefinidos en la plataforma que podemos utilizar para dar formato al texto, entre ellos: TypefaceSpan. Modifica el tipo de fuente. StyleSpan. Modifica el estilo del texto (negrita, cursiva, ). ForegroudColorSpan. Modifica el color del texto. AbsoluteSizeSpan. Modifica el tamao de fuente.
De esta forma, para crear un nuevo objeto Editable e insertar una marca de formato podramos hacer lo siguiente:
//Creamos un nuevo objeto de tipo Editable Editable str = Editable.Factory.getInstance().newEditable("Esto es un simulacro."); //Marcamos cono fuente negrita la palabra "simulacro" str.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 11, 19, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Insertamos un span de tipo StyleSpan para marcar un fragmento de texto con estilo negrita. Para insertarlo utilizamos el
26
2.
mtodo setSpan(), que recibe como parmetro el objeto Span a insertar, la posicin inicial y final del texto a marcar, y un flag que indica la forma en la que el span se podr extender al insertarse nuevo texto. Actividad Realizar una aplicacin en Android en la que colocars un cuadro de texto, un botn y una etiqueta de tal manera que se inserte en el cuadro de texto un DNI y al pulsar en el botn mostrar la letra del DNI. Comprobar que el DNI insertado sea correcto (8 dgitos). El algoritmo se basa en realizar el mdulo entre el nmero del DNI y el 23 y el resultado obtenido se busca en la siguiente tabla la letra que corresponde. 0 T 1 2 3 4 5 6 R W A G M Y 7 F 8 P 9 10 11 12 13 14 15 16 17 18 19 20 21 22 D X B N J Z S Q V H L C K E
Actividad
Realizar una aplicacin en Android en la que 2 cuadros de texto, 6 botones y una etiqueta de tal forma que emule una bsica calculadora que sume, reste, multiplique y divida. Los dos botones restantes son para el igual y borrar los dos cuadros de texto y la etiqueta, que es donde se pondr el resultado final. Para utilizar el teclado numrico en un cuadro de texto se debe incorporar el siguiente cdigo:
<EditText android:numeric="integer" android:inputType="number"> </EditText>
En el cdigo de la aplicacin podremos hacer uso de los mtodos isChecked() para conocer el estado del control, y setChecked(estado) para establecer un estado concreto para el control.
if (checkBox.isChecked()) { checkBox.setChecked(false); }
En cuanto a los posibles eventos que puede lanzar este control, el ms interesante es sin duda el que informa de que ha cambiado el estado del control, que recibe el nombre de onCheckedChanged. Para implementar las acciones de este evento podramos utilizar por tanto la siguiente lgica:
final CheckBox cb = (CheckBox)findViewById(R.id.chkMarcame); cb.setOnCheckedChangeListener( new CheckBox.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { cb.setText("Checkbox marcado!"); } else { cb.setText("Checkbox desmarcado!");
27
2.
} } });
RADIOBUTTON Al igual que los controles CheckBox, un RadioButton puede estar marcado o desmarcado, pero en este caso suelen utilizarse dentro de un grupo de opciones donde una, y slo una, de ellas debe estar marcada obligatoriamente, es decir, que si se marca una de ellas se desmarcar automticamente la que estuviera activa anteriormente. En Android, un grupo de botones RadioButton se define mediante un elemento RadioGroup, que a su vez contendr todos los elementos RadioButton necesarios. Veamos un ejemplo de cmo definir un grupo de dos controles RadioButton en nuestra interfaz:
<RadioGroup android:id="@+id/gruporb" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <RadioButton android:id="@+id/radio1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Opcin 1" /> <RadioButton android:id="@+id/radio2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Opcin 2" /> </RadioGroup>
En primer lugar vemos cmo podemos definir el grupo de controles indicando su orientacin (vertical u horizontal) al igual que ocurra por ejemplo con un LinearLayout. Tras esto, se aaden todos los objetos RadioButton necesarios indicando su ID mediante la propiedad android:id y su texto mediante android:text. Una vez definida la interfaz podremos manipular el control desde nuestro cdigo java haciendo uso de los diferentes mtodos del control RadioGroup, los ms importantes: check(id) para marcar una opcin determinada mediante su ID, clearCheck() para desmarcar todas las opciones, y getCheckedRadioButtonId() que como su nombre indica devolver el ID de la opcin marcada (o el valor -1 si no hay ninguna marcada). Veamos un ejemplo:
final RadioGroup rg = (RadioGroup)findViewById(R.id.gruporb); rg.clearCheck(); rg.check(R.id.radio1); int idSeleccionado = rg.getCheckedRadioButtonId();
En cuanto a los eventos lanzados, al igual que en el caso de los checkboxes, el ms importante ser el que informa de los cambios en el elemento seleccionado, llamado tambin en este caso onCheckedChange. Vemos cmo tratar este evento del objeto RadioGroup:
final RadioGroup rg = (RadioGroup)findViewById(R.id.gruporb); rg.setOnCheckedChangeListener( new RadioGroup.OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { lblMensaje.setText("ID opcion seleccionada: " + checkedid); } });
B - CONTROLES DE SELECCIN
Veamos los controles que permiten seleccionar una opcin dentro de una lista de posibilidades. As, podremos utilizar listas desplegables (Spinner), listas fijas (ListView), tablas (GridView) y otros controles especficos de la plataforma como por ejemplo las galeras de imgenes (Gallery). Empezamos describiendo un elemento importante y comn a todos ellos, los adaptadores, y lo vamos a aplicar al primer control de los indicados, las listas desplegables.
28
2.
ADAPTADORES (ADAPTERS) Un adaptador representa Una interfaz comn al modelo de datos que existe por detrs de todos los controles de seleccin comentados. Dicho de otra forma, todos los controles de seleccin accedern a los datos que contienen a travs de un adaptador. Adems de proveer de datos a los controles visuales, el adaptador tambin ser responsable de generar a partir de estos datos las vistas especficas que se mostrarn dentro del control de seleccin. Por ejemplo, si cada elemento de una lista estuviera formado a su vez por una imagen y varias etiquetas, el responsable de generar y establecer el contenido de todos estos sub-elementos a partir de los datos ser el propio adaptador. Android proporciona de serie varios tipos de adaptadores sencillos. Los ms comunes son: ArrayAdapter. Es el ms sencillo de todos los adaptadores, y provee de datos a un control de seleccin a partir de un array de objetos de cualquier tipo. SimpleAdapter. Se utiliza para mapear datos sobre los diferentes controles definidos en un fichero XML de layout. SimpleCursorAdapter. Se utiliza para mapear las columnas de un cursor sobre los diferentes elementos visuales contenidos en el control de seleccin.
Sobre el cdigo comentar que inicialmente declaramos un vector de ristras con los elementos que querramos que sean las opciones de seleccin. Y en la segunda lnea declaramos el adaptador con 3 parmetros: el primero de todos es una referencia a la actividad donde se declara el adaptador. El segundo ser el layout donde se mostrar dicho elemento y en tercer lugar el vector de ristras que tiene los datos a mostrar. SPINNER De esta manera se conoce a las listas desplegables en Android. Funcionan de forma similar al de cualquier control de este tipo, el usuario selecciona la lista, se muestra una especie de lista emergente al usuario con todas las opciones disponibles y al seleccionarse una de ellas sta queda fijada en el control. Para aadir una lista de este tipo a nuestra aplicacin podemos utilizar el cdigo siguiente:
<Spinner android:id="@+id/CmbOpciones" android:layout_width="fill_parent" android:layout_height="wrap_content" />
Para enlazar nuestro adaptador (y por tanto nuestros datos) a este control utilizaremos el siguiente cdigo JAVA:
final Spinner cmbOpciones = (Spinner)findViewById(R.id.CmbOpciones); adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); cmbOpciones.setAdapter(adaptador);
Comenzamos como siempre por obtener una referencia al control a travs de su ID. Y en la ltima lnea asignamos el adaptador al control mediante el mtodo setAdapter(). La segunda lnea es para indicar el parmetro que le pasbamos para visualizar los elementos del control. Sin embargo, en el caso del control Spinner, este layout tan slo se aplicar al elemento seleccionado en la lista, es decir, al que se muestra directamente sobre el propio control cuando no est desplegado. Sin embargo, antes indicamos que el funcionamiento normal del control Spinner incluye entre otras cosas mostrar una lista emergente con todas las opciones disponibles.
29
2.
Pues bien, para personalizar tambin el aspecto de cada elemento en dicha lista emergente tenemos el mtodo setDropDownViewResource(ID_layout), al que podemos pasar otro ID de layout distinto al primero sobre el que se mostrarn los elementos de la lista emergente. En este caso hemos utilizado otro layout predefinido en Android para las listas desplegables (android.R.layout.simple_spinner_dropdown_item). La representacin del elemento seleccionado y el de las opciones disponibles es distinto. Esto es debido a la utilizacin de dos layouts diferentes para uno y otros elementos. En cuanto a los eventos lanzados por el control Spinner, el ms comunmente utilizado ser el generado al seleccionarse una opcin de la lista desplegable, onItemSelected. Para capturar este evento se proceder de forma similar a lo ya visto para otros controles anteriormente, asignadole su controlador mediante el mtodo setOnItemSelectedListener():
cmbOpciones.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, android.view.View v, int position, long id) { lblMensaje.setText("Seleccionado: " + datos[position]); } public void onNothingSelected(AdapterView<?> parent) { lblMensaje.setText(""); } });
B2. LISTVIEW
LISTVIEW Un control ListView muestra al usuario una lista de opciones seleccionables directamente sobre el propio control, sin listas emergentes como en el caso del control Spinner. En caso de existir ms opciones de las que se pueden mostrar sobre el control se podr por supuesto hacer scroll sobre la lista para acceder al resto de elementos. Para su inclusin mediante XML ser:
<ListView android:id="@+id/LstOpciones" android:layout_width="wrap_content" android:layout_height="wrap_content" />
30
2.
Hasta este punto todo es exactamente igual a un Spinner. Y qu pasa si queremos mostrar datos ms complejos en nuestra seleccin. Para no complicar mucho el asunto vamos a hacer que cada elemento de la lista muestre dos lneas de texto a modo de ttulo y subttulo con formatos diferentes aunque se pueden aadir ms cosa. En primer lugar vamos a crear una nueva clase java para contener nuestros datos de prueba. Vamos a llamarla Titular y tan slo va a contener dos atributos, ttulo y subttulo.
package net.listaelementos; public class Titular { private String titulo; private String subtitulo; public Titular(String tit, String sub){ titulo = tit; subtitulo = sub; } public String getTitulo(){ return titulo; } public String getSubtitulo(){ return subtitulo; } }
En cada elemento de la lista queremos mostrar ambos datos, por lo que el siguiente paso ser crear un layout XML con la estructura que deseemos. En mi caso voy a mostrarlos en dos etiquetas de texto ( TextView), la primera de ellas en negrita y con un tamao de letra un poco mayor. Llamaremos a este layout listitem_titular.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/LblTitulo" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textStyle="bold" android:textSize="20px" /> <TextView android:id="@+id/LblSubTitulo" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textStyle="normal" android:textSize="12px" /> </LinearLayout>
Ahora que ya tenemos creados tanto el soporte para nuestros datos como el layout que necesitamos para visualizarlos, lo siguiente que debemos hacer ser indicarle al adaptador cmo debe utilizar ambas cosas para generar nuestra interfaz de usuario final. Para ello vamos a crear nuestro propio adaptador extendiendo de la clase ArrayAdapter.
31
2.
class AdaptadorTitulares extends ArrayAdapter { Activity context; AdaptadorTitulares(Activity context) { super(context, R.layout.listitem_titular, datos); this.context = context; } public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = context.getLayoutInflater(); View item = inflater.inflate(R.layout.listitem_titular, null); TextView lblTitulo = (TextView)item.findViewById(R.id.LblTitulo); lblTitulo.setText(datos[position].getTitulo()); TextView lblSubtitulo = (TextView)item.findViewById(R.id.LblSubTitulo); lblSubtitulo.setText(datos[position].getSubtitulo()); return(item); } }
Analicemos el cdigo anterior. Lo primero que encontramos es el constructor para nuestro adaptador, al que slo pasaremos el contexto (que ser la actividad desde la que se crea el adaptador). En este constructor tan slo guardaremos el contexto para nuestro uso posterior y llamaremos al constructor padre tal como ya vimos al principio de este artculo, pasndole el ID del layout que queremos utilizar (en nuestro caso el nuevo que hemos creado, listitem_titular) y el array que contiene los datos a mostrar. Posteriormente, redefinimos el mtodo encargado de generar y rellenar con nuestros datos todos los controles necesarios de la interfaz grfica de cada elemento de la lista. Este mtodo es getView(). El mtodo getView() se llamar cada vez que haya que mostrar un elemento de la lista. Lo primero que debe hacer es inflar el layout XML que hemos creado. Esto consiste en consultar el XML de nuestro layout y crear e inicializar la estructura de objetos java equivalente. Para ello, crearemos un nuevo objeto LayoutInflater y generaremos la estructura de objetos mediante su mtodo inflate(id_layout). Tras esto, tan slo tendremos que obtener la referencia a cada una de nuestras etiquetas como siempre lo hemos hecho y asignar su texto correspondiente segn los datos de nuestro array y la posicin del elemento actual (parmetro position del mtodo getView()). Una vez tenemos definido el comportamiento de nuestro adaptador la forma de proceder en la actividad principal ser anloga a lo ya comentado, definiremos el array de datos de prueba, crearemos el adaptador y lo asignaremos al control mediante setAdapter():
private Titular[] datos = new Titular[]{ new Titular("Ttulo new Titular("Ttulo new Titular("Ttulo new Titular("Ttulo new Titular("Ttulo //... //... AdaptadorTitulares adaptador = new AdaptadorTitulares(this); ListView lstOpciones = (ListView)findViewById(R.id.LstOpciones); lstOpciones.setAdapter(adaptador);
32
2.
B3. GRIDVIEW
GRIDVIEW Es un control menos utilizado que el Spinner o el ListView pero no por ello debemos menospreciarlo. El control GridView de Android presenta al usuario un conjunto de opciones seleccionables distribuidas de forma tabular, o dicho de otra forma, divididas en filas y columnas. Dada la naturaleza del control ya podis imaginar sus propiedades ms importantes, que paso a enumerar a continuacin: - android:numColumns, indica el nmero de columnas de la tabla o auto_fit si queremos que sea calculado por el propio sistema operativo a partir de las siguientes propiedades. - android:columnWidth, indica el ancho de las columnas de la tabla. - android:horizontalSpacing, indica el espacio horizontal entre celdas. - android:verticalSpacing, indica el espacio vertical entre celdas. - android:stretchMode, indica qu hacer con el espacio horizontal sobrante. Si se establece al valor columnWidth este espacio ser absorbido a partes iguales por las columnas de la tabla. Si por el contrario se establece a spacingWidth ser absorbido a partes iguales por los espacios entre celdas. Veamos cmo definiramos un GridView de ejemplo en nuestra aplicacin:
<GridView android:id="@+id/GridOpciones" android:layout_width="fill_parent" android:layout_height="fill_parent" android:numColumns="auto_fit" android:columnWidth="80px" android:horizontalSpacing="5px" android:verticalSpacing="10px" android:stretchMode="columnWidth" />
Una vez definida la interfaz de usuario, la forma de asignar los datos desde el cdigo de la aplicacin es completamente anloga a la ya comentada tanto para las listas desplegables como para las listas estticas: creamos un vector genrico que contenga nuestros datos de prueba, declaramos un adaptador de tipo ArrayAdapter pasndole en este caso un layout genrico (simple_list_item_1, compuesto por un simple TextView) y asociamos el adaptador al control GridView mediante su mtodo setAdapter():
private String[] datos = new String[25]; //... for(int i=1; i<=25; i++) datos[i-1] = "Dato " + i; ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, datos); final GridView grdOpciones = (GridView)findViewById(R.id.GridOpciones); grdOpciones.setAdapter(adaptador);
Por defecto, los datos del vector se aadirn al control GridView ordenados por filas, y por supuesto, si no caben todos en la pantalla se podr hacer scroll sobre la tabla. En cuanto a los eventos disponibles, el ms interesante vuelve a ser el lanzado al seleccionarse una celda determinada de la tabla: onItemSelected. Este evento podemos capturarlo de la misma forma que hacamos con los controles Spinner y ListView. Veamos un ejemplo de cmo hacerlo:
grdOpciones.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, android.view.View v, int position, long id) { lblMensaje.setText("Seleccionado: " + datos[position]); } public void onNothingSelected(AdapterView<?> parent) { lblMensaje.setText(""); } });
33
2.
C TAB LAYOUT
Dado el poco espacio con el que contamos en las pantallas de muchos dispositivos o por cuestiones de organizacin, a veces es conveniente dividir nuestros controles en varias pantallas. Y una de las formas clsicas de conseguir esto consiste en la distribucin de los elementos por pestaas o Tabs. Android por supuesto permite utilizar este tipo de interfaces, aunque lo hace de una forma un tanto peculiar, ya que la implementacin no va a depender de un slo elemento sino de varios que deben estar distribuidos y estructurados de una forma determinada la cual no es arbitraria. Adicionalmente no nos bastar simplemente con definir la interfaz en XML como hemos hecho en otras ocasiones, sino que tambin necesitaremos completar el conjunto con algunas lneas de cdigo. El elemento principal de un conjunto de pestaas ser el control TabHost. ste va a ser el contenedor principal de nuestro conjunto de pestaas y deber tener obligatoriamente como id el valor @android:id/tabhost. Dentro de ste vamos a incluir un LinearLayout que nos servir para distribuir verticalmente las secciones principales del layout: la seccin de pestaas en la parte superior y la seccin de contenido en la parte inferior. La seccin de pestaas se representar mediante un elemento TabWidget, que deber tener como id el valor @android:id/tabs, y como contenedor para el contenido de las pestaas aadiremos un FrameLayout con el id obligatorio @android:id/tabcontent. Por ltimo, dentro del FrameLayout incluiremos el contenido de cada pestaa, normalmente cada uno dentro de su propio layout principal con un id nico que nos permita posteriormente hacer referencia a ellos fcilmente. Grficamente se representa de la siguiente forma:
34
2.
<LinearLayout android:id="@+id/tab1" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView1" android:text="Contenido Tab 1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:id="@+id/tab2" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView2" android:text="Contenido Tab 2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </FrameLayout> </LinearLayout> </TabHost>
Necesitamos asociar de alguna forma cada pestaa con su contenido, de forma que el el control se comporte correctamente cuando cambiamos de pestaa. Y esto tendremos que hacerlo mediante cdigo en nuestra actividad principal. Empezaremos obteniendo una referencia al control principal TabHost y preparndolo para su configuracin llamando a su mtodo setup(). Tras esto, crearemos un objeto de tipo TabSpec para cada una de las pestaas que queramos aadir mediante el mtodo newTabSpec(), al que pasaremos como parmetro una etiqueta identificativa de la pestaa. Adems, tambin le asignaremos el layout de contenido correspondiente a la pestaa llamando al mtodo setContent(), e indicaremos el texto y el icono que queremos mostrar en la pestaa mediante el mtodo setIndicator(texto, icono). Este cdigo se introduce dentro del evento onCreate y se importa las libreras necesarias.
Resources res = getResources(); TabHost tabs=(TabHost)findViewById(android.R.id.tabhost); tabs.setup(); TabHost.TabSpec spec=tabs.newTabSpec("mitab1"); spec.setContent(R.id.tab1); spec.setIndicator("TAB1", res.getDrawable(android.R.drawable.ic_btn_speak_now)); tabs.addTab(spec); spec=tabs.newTabSpec("mitab2"); spec.setContent(R.id.tab2); spec.setIndicator("TAB2", res.getDrawable(android.R.drawable.ic_dialog_map)); tabs.addTab(spec); tabs.setCurrentTab(0);
En cuanto a los eventos disponibles del control TabHost, aunque no suele ser necesario capturarlos, podemos ver a modo de ejemplo el ms interesante de ellos, OnTabChanged, que se lanza cada vez que se cambia de pestaa y que nos informa de la nueva pestaa que se visualiza. Este evento podemos implementarlo y asignarlo mediante el mtodo setOnTabChangedListener() de la siguiente forma:
tabs.setOnTabChangedListener(new OnTabChangeListener() { @Override public void onTabChanged(String tabId) { Log.i("AndroidTabsDemo", "Pulsada pestaa: " + tabId); } });
35
2.
Hay que importar la librera: import android.widget.TabHost.OnTabChangeListener; En el mtodo onTabChanged() recibimos como parmetro la etiqueta identificativa de la pestaa (no su ID), que debimos asignar cuando creamos su objeto TabSpec correspondiente. Para este ejemplo, lo nico que haremos al detectar un cambio de pestaa ser escribir en el log de la aplicacin un mensaje informativo con la etiqueta de la nueva pestaa visualizada. As por ejemplo, al cambiar a la segunda pestaa recibiremos el mensaje de log: Pulsada pestaa: mitab2.
D MENS
En Android podemos encontrar 3 tipos diferentes de mens: Mens Principales. Los ms habituales, aparecen en la zona inferior de la pantalla al pulsar el botn menu del telfono. Submens. Son mens secundarios que se pueden mostrar al pulsar sobre una opcin de un men principal. Mens Contextuales. tiles en muchas ocasiones, aparecen al realizar una pulsacin larga sobre algn elemento de la pantalla.
Vamos a ver las 2 posibilidades de creacin que existen. La primera mediante la definicin del fichero XML y la segunda mediante la implementacin a travs de cdigo. Empecemos mediante XML. Los ficheros XML de men se deben colocar en la carpeta res\menu de nuestro proyecto y tendrn una estructura anloga a la del siguiente ejemplo:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/MnuOpc1" android:title="Opcion1" android:icon="@drawable/tag"></item> <item android:id="@+id/MnuOpc2" android:title="Opcion2" android:icon="@drawable/filter"></item> <item android:id="@+id/MnuOpc3" android:title="Opcion3" android:icon="@drawable/chart"></item> </menu>
Como vemos, la estructura bsica de estos ficheros es muy sencilla. Tendremos un elemento principal <menu> que contendr una serie de elementos <item> que se correspondern con las distintas opciones a mostrar en el men. Estos elementos <item> tendrn a su vez varias propiedades bsicas, como su ID (android:id), su texto (android:title) o su icono (android:icon). Los iconos utilizados debern estar por supuesto en las carpetas res \drawable- de nuestro proyecto (al final del artculo Una vez definido el men en el fichero XML, tendremos que implementar el evento onCreateOptionsMenu() de la actividad que queremos que lo muestre. En este evento deberemos inflar el men de forma parecida a cmo ya hemos hecho otras veces con otro tipo de layouts. Primero obtendremos una referencia al inflater mediante el mtodo getMenuInflater() y posteriormente generaremos la estructura del men llamando a su mtodo inflate() pasndole como parmetro el ID del menu definido en XML, que en nuestro caso ser R.menu.menu_principal. Cuidado con que no coincida el nombre con el del XML que define el layout. Por ltimo devolveremos el valor true para confirmar que debe mostrarse el men.
@Override public boolean onCreateOptionsMenu(Menu menu) { //Alternativa 1 MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_principal, menu); return true; }
Como hemos comentado antes, este mismo men tambin lo podramos crear directamente mediante cdigo, tambin desde el evento onCreateOptionsMenu(). Para ello, para aadir cada opcin del men podemos utilizar el mtodo add() sobre el objeto de tipo Menu que nos llega como parmetro del evento.
36
2.
Este mtodo recibe 4 parmetros: ID del grupo asociado a la opcin (veremos qu es esto en el siguiente artculo, por ahora utilizaremos Menu.NONE), un ID nico para la opcin (que declararemos como constantes de la clase), el orden de la opcin (que no nos interesa por ahora, utilizaremos Menu.NONE) y el texto de la opcin. Por otra aprte, el icono de cada opcin lo estableceremos mediante el mtodo setIcon() pasndole el ID del recurso. Veamos cmo quedara el cdigo utilizando esta alternativa, que generara un men exactamente igual al del ejemplo anterior:
private static final int MNU_OPC1 = 1; private static final int MNU_OPC2 = 2; private static final int MNU_OPC3 = 3; //... @Override public boolean onCreateOptionsMenu(Menu menu) { //Alternativa 2 menu.add(Menu.NONE, MNU_OPC1, Menu.NONE, "Opcion1").setIcon(R.drawable.tag); menu.add(Menu.NONE, MNU_OPC2, Menu.NONE, "Opcion2").setIcon(R.drawable.filter); menu.add(Menu.NONE, MNU_OPC3, Menu.NONE, "Opcion3").setIcon(R.drawable.chart); return true; }
Construido el men, la implementacin de cada una de las opciones se incluir en el evento onOptionsItemSelected() de la actividad que mostrar el men. Este evento recibe como parmetro el item de men que ha sido pulsado por el usuario, cuyo ID podemos recuperar con el mtodo getItemId(). Segn este ID podremos saber qu opcin ha sido pulsada y ejecutar unas acciones u otras. En nuestro caso de ejemplo, lo nico que haremos ser modificar el texto de una etiqueta (lblMensaje) colocada en la pantalla principal de la aplicacin.
@Override public boolean onOptionsItemSelected(MenuItem item) { TextView tv=(TextView)findViewById(R.id.lblMensaje); switch (item.getItemId()) { case 1: lblMensaje.setText("Opcion 1 pulsada!"); return true; case 2: lblMensaje.setText("Opcion 2 pulsada!");; return true; case 3: lblMensaje.setText("Opcion 3 pulsada!");; return true; default: return super.onOptionsItemSelected(item); } }
E LLAMANDO A ACTIVIDADES
Vamos a explicar el desarrollo de una pequea aplicacin pero que muestra uno de los conceptos ms importantes. La llamada desde una actividad a otras. La idea que vamos a realizar es una aplicacin formada por 2 actividades o ventana. En ambas habr una etiqueta y en la primera actividad un botn. Cada etiqueta mostrar un texto en el que se indique el nombre de la ventana en la que nos encontramos. Algo parecido a Ventana nmero 1 y el botn har que pasemos a la s egunda actividad. Lo primero que vamos a realizar es crear un nuevo proyecto Android denominado Manejando_Actividades. En la primera actividad que es la nos sale inicialmente vamos a poner un TextView llamado etiqueta1 y un Button llamado boton1. Lo siguiente que tenemos que realizar es aadir el archivo XML de la otra actividad y en su interior incorporar los elementos que configurarn su diseo.
37
2.
Para ello lo que hacemos es pinchar con el botn derecho del ratn en la carpeta /res/layout y pulsaremos la opcin New Android XML File. Lo hacemos y lo llamamos actividad2. En ella vamos a poner un TextView llamado etiqueta2. Lo siguiente que tenemos que realizar es implementar el cdigo correspondiente para los archivos java asociados a cada actividad. Para la primera ya tenemos por defecto el archivo creado pues lo hace el Eclipse al crear el proyecto. Este se llamar MainActivity.java Lo siguiente que tenemos que realizar es crear el archivo java asociado con la segunda actividad de la cul ya hemos creado. Para ello pulsaremos dentro de la carpeta /src, en el nombre del paquete que hemos puesto con el botn derecho del ratn y elegiremos New Class. Pondremos el nombre que querramos. En este caso Acitividad2.java Modificaremos el cdigo que tiene para que quede algo como lo siguiente:
package com.example.manejando_Actividades; import android.app.Activity; import android.os.Bundle; public class Actividad2 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actividad2); } }
El proceso de creacin del XML y del archivo java se puede tambin realizar en Eclipse de manera ms directa eligiendo New Other Android Android Activity Nos vamos a la implementacin de nuestra primera actividad. Vamos al MainActivity.java y ponemos el cdigo para crear la etiqueta y el botn. Una vez hecho esto, implementamos el cdigo del evento onclick del botn para implementar el cdigo para que al pulsar en dicho botn nos lleve a la segunda actividad. Vamos y dentro del oncreate ponemos:
boton1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //Creamos el Intent Intent intent = new Intent(MainActivity.this, FrmSaludo.class); //Iniciamos la nueva actividad startActivity(intent); } });
En nuestro archivo de implementacin de la actividad 2 debemos crear la etiqueta. Falta por incorporar a nuestro archivo AndroidManifest.xml la segunda actividad que hemos aadido y conforma nuestra aplicacin. Nos vamos a dicho archivo y dentro de este, a la pestaa AndroidManifest.xml En ella, aadimos la actividad. Quedara algo como:
<activity android:name=".Actividad2" android:label="Actividad 2" > </activity>
38
2.
E1. BUNDLE
Imaginemos que queremos pasar datos entre estas actividades de la aplicacin anterior. Para ello tenemos el tipo Bundle. Supongamos que en nuestra aplicacin anterior, en la primera actividad aadimos un EditText y en la segunda actividad creamos un TextView ms en la cul se mostrar lo que se haya introducido en el EditText de la primera ventana si introdujo algo y si no que muestre No se pasa nada. Para ello, lo primero que debemos hacer es aadir los componentes necesarios que los archivos XML necesarios. A continuacin nos vamos a la primera actividad, la cul es la que va a enviar los datos y en esta actividad, antes de hacer la llamada a la siguiente actividad creamos el objeto Bundle y en l ponemos la informacin que queremos enviar asignndole a un nombre de elemento de informacin. Una vez aadido cada elemento de informacin con la informacin a traspasar, simplemente hay que poner dicho objeto Bundle en el intent que se ha creado. El cdigo quedara como sigue:
//Creamos la informacin a pasar entre actividades Bundle b = new Bundle(); b.putString("valor", texto1.getText().toString()); //Aadimos la informacin al intent intent.putExtras(b);
Lo siguiente a realizar ser en la segunda actividad, que es a la que se llama, recibir los datos que se le envan. Esto lo hacemos de la siguiente manera:
//Recuperamos la informacin pasada en el intent Bundle bundle = this.getIntent().getExtras(); //Construimos el mensaje a mostrar if (bundle.getString("valor").trim().equals("")) { etiqueta3.setText("No se pasa nada."); } else etiqueta3.setText(bundle.getString("valor"));
Lo que hacemos es crear un objeto nuevamente de tipo Bundle en el cul recuperamos los datos y lo siguiente es usar dicho valor en el objeto que querramos. En el caso anterior, en la etiqueta3.
39