<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>La columna 80</title>
	<atom:link href="https://columna80.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://columna80.wordpress.com</link>
	<description>El blog técnico-personal de Ángel J. Vico... en español</description>
	<lastBuildDate>Sun, 28 Apr 2013 11:48:32 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<site xmlns="com-wordpress:feed-additions:1">14823439</site><cloud domain='columna80.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>https://secure.gravatar.com/blavatar/7d876748046f7af6ebeaa6f93bf6a9b61eb33c02f4df8d3c18467125ea40dc56?s=96&#038;d=https%3A%2F%2Fs2.wp.com%2Fi%2Fwebclip.png</url>
		<title>La columna 80</title>
		<link>https://columna80.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="https://columna80.wordpress.com/osd.xml" title="La columna 80" />
	<atom:link rel='hub' href='https://columna80.wordpress.com/?pushpress=hub'/>
	<item>
		<title>Instalaci&#243;n de una m&#225;quina virtual Android</title>
		<link>https://columna80.wordpress.com/2013/04/28/instalacin-de-una-mquina-virtual-android/</link>
					<comments>https://columna80.wordpress.com/2013/04/28/instalacin-de-una-mquina-virtual-android/#respond</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Sun, 28 Apr 2013 11:39:38 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[VirtualBox]]></category>
		<category><![CDATA[máquinas virtuales]]></category>
		<category><![CDATA[SDK]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=906</guid>

					<description><![CDATA[Cuando desarrollamos para Android nos vemos en la necesidad de probar nuestras aplicaciones en diversos dispositivos, para garantizar su correcto funcionamiento en configuraciones diferentes. Salvo que dispongamos de muchos y variados dispositivos reales, no nos quedará más remedio que emularlos. El SDK de Android nos permite crear AVDs (Android Virtual Devices) para diversas versiones del [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;">Cuando desarrollamos para Android nos vemos en la necesidad de probar nuestras aplicaciones en diversos dispositivos, para garantizar su correcto funcionamiento en configuraciones diferentes. Salvo que dispongamos de muchos y variados dispositivos reales, no nos quedará más remedio que emularlos.</p>
<p style="text-align:justify;">El SDK de Android nos permite crear AVDs (<i>Android Virtual Devices</i>) para diversas versiones del sistema operativo y con variadas características hardware. Pero, seamos realistas, su rendimiento deja bastante que desear, incluso en máquinas potentes.</p>
<p style="text-align:justify;">A medida que van saliendo nuevas versiones de Android el esfuerzo que tiene que realizar el software para emularlas es cada vez mayor, lo que provoca que se ejecuten con bastante lentitud. Y mejor no hablemos de tabletas. Para arrancar un AVD con configuración de tableta hay que armarse de paciencia.</p>
<p style="text-align:justify;">Afortunadamente, tenemos otra opción para emular Android obteniendo un mayor rendimiento: usar una máquina virtual que ejecuta la versión para procesadores Intel x86 de Android. Hay varios proyectos que buscan la mejor forma de realizar esta tarea. Yo me voy a centrar en AndroidVM, que es una de las soluciones más sencillas.</p>
<p><span id="more-906"></span></p>
<h3><a name="h.1gy769lzkbrh"></a>Descargando todo lo necesario</h3>
<p style="text-align:justify;">Lo primero que hay que descargar es la imagen de la máquina que vamos a instalar. Lo podemos hacer desde <a href="http://androvm.org/blog/download/">http://androvm.org/blog/download/</a>. Hay varias versiones:</p>
<ul>
<li>
<p style="text-align:justify;">Versión para emular teléfonos: vbox86p</p>
</li>
<li>
<p style="text-align:justify;">Versión para emular tabletas: vbox86t</p>
</li>
<li>
<p style="text-align:justify;">Versión para emular tabletas con capacidades de teléfono: vbox86tp</p>
</li>
</ul>
<p style="text-align:justify;">Además, de cada una de ellas hay una versión básica y otra que incluye las aplicaciones de Google, Houdini (un emulador de ARM) y soporte Flash. Lo del emulador de ARM se debe a que las imágenes son de Android para x86 y algunas aplicaciones se ejecutan en modo nativo y están compiladas para ARM (por ejemplo, el reproductor flash).</p>
<p style="text-align:justify;">La imagen la descargamos en formato OVA (<i>Open Virtualization Appliance</i>), que es un paquete OVF (<i>Open Virtualization Format</i>) comprimido. El paquete contiene varias imágenes de disco y un fichero descriptor en formato XML. Las imágenes de disco de estos paquetes AndroVM están en formato VMDK (<i>Virtual Machine Disk</i>). Es el formato que utilizan los productos de VMware, pero también lo soporta <a href="https://columna80.wordpress.com/virtualbox/" target="_blank">VirtualBox</a>, que es el que utilizaré en este post.</p>
<p style="text-align:justify;">En esa misma página también es recomendable descargar la aplicación <strong>AndroVM Player</strong>, que nos servirá para que la máquina virtual utilice el hardware gráfico de la máquina anfitriona. Conviene descargar la versión que se corresponda con la versión de Windows que tengamos, 32 o 64 bits. No requiere instalación, basta con descomprimirla en un directorio.</p>
<h3><a name="h.1epd6vvo654m"></a>Instalación de la máquina virtual</h3>
<p style="text-align:justify;">Instalar la imagen que hemos descargado es fácil y rápido. Basta con hacer doble click sobre ella o seleccionar <b>Archivo</b> | <b>Importar servicio virtualizado</b> en VirtualBox. Aceptamos las opciones predeterminadas y ya tenemos la máquina instalada.</p>
<p style="text-align:justify;">Sencillo, ¿verdad?</p>
<h3><a name="h.q5a8yrhcqfh7"></a>Configuración de VirtualBox</h3>
<p style="text-align:justify;">La última versión de AndroVM Player es capaz de configurar la máquina virtual de forma automática la primera vez que se ejecuta, por lo que podemos saltarnos este apartado y los dos siguientes y pasar directamente a la configuración de AndroVM Player.</p>
<p style="text-align:justify;">Aún así, como las cosas no siempre funcionan como debieran, explicaré aquí la forma “manual” de hacerlo, por si tuviéramos que recurrir a ella.</p>
<p style="text-align:justify;">Para poder comunicarnos con la máquina virtual desde la anfitriona necesitamos un adaptador sólo-anfitrión (<i>host-only</i>). Para ver qué adaptadores tenemos configurados abrimos VirtualBox y seleccionamos <b>Archivo</b> | <b>Preferencias</b>. En la ventana que se abre seleccionamos <b>Red</b>:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-01-configuracin-de-red-de-virtualbox.png" target="_blank"><img style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="Configuración de red de VirtualBox" alt="Configuración de red de VirtualBox" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-01-configuracin-de-red-de-virtualbox_thumb.png?w=244&#038;h=184" width="244" height="184" border="0" /></a></p>
<p style="text-align:justify;">Seguramente habrá uno ya creado y podremos utilizarlo. Si no hay ninguno, o si no queremos mezclar redes, podemos añadir uno (usando el botón superior de la derecha). Lo importante es que tenga activo el servidor DHCP. Para comprobarlo hay que abrir los detalles del adaptador, haciendo doble click sobre él. Luego pulsamos en la pestaña <b>Servidor DHCP</b>:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-02-detalles-de-red-slo-anfitrin-adaptador.png" target="_blank"><img style="background-image:none;padding-top:0;padding-left:0;margin:5px 0;display:inline;padding-right:0;border-width:0;" title="Detalles de red sólo-anfitrión - Adaptador" alt="Detalles de red sólo-anfitrión - Adaptador" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-02-detalles-de-red-slo-anfitrin-adaptador_thumb.png?w=244&#038;h=136" width="244" height="136" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-03-detalles-de-red-slo-anfitrin-servidor-dhcp.png" target="_blank"><img style="background-image:none;padding-top:0;padding-left:0;margin:5px 0;display:inline;padding-right:0;border-width:0;" title="Detalles de red sólo-anfitrión - Servidor DHCP" alt="Detalles de red sólo-anfitrión - Servidor DHCP" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-03-detalles-de-red-slo-anfitrin-servidor-dhcp_thumb.png?w=244&#038;h=136" width="244" height="136" border="0" /></a></p>
<p style="text-align:justify;">Hay que seleccionar <b>Habilitar servidor</b> y rellenar los datos. Se escoge una dirección para el servidor, se pone una máscara de tipo C (255.255.255.0) y luego se establece un rango de direcciones para las máquinas virtuales, teniendo cuidado de que no incluya la asignada al servidor.</p>
<h3><a name="h.4jebhmf3caem"></a>Configuración de la máquina virtual</h3>
<p style="text-align:justify;">El siguiente paso es configurar la máquina virtual. La seleccionamos en VirtualBox y pulsamos el botón <b>Configuración</b>. Hay que seleccionar <b>Red</b> en el menú de la izquierda.</p>
<p style="text-align:justify;">La máquina virtual viene configurada con dos adaptadores de red. Uno lo utiliza para conectarse a Internet y el otro está disponible para poder conectarlo con la máquina anfitriona. Este último viene desactivado, así que tenemos que configurarlo. Para ello, en la pestaña <b>Adaptador 1</b> hay que cambiar la lista desplegable <b>Conectado a</b> de <b>No conectado</b> a <b>Adaptador sólo-anfitrión</b>. Luego, en <b>Nombre</b> seleccionamos el adaptador que configuramos antes.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-04-confiuracin-de-red-de-androvm-en-virtualbox.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="Confiuración de red de androVM en VirtualBox" alt="Confiuración de red de androVM en VirtualBox" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-04-confiuracin-de-red-de-androvm-en-virtualbox_thumb.png?w=244&#038;h=174" width="244" height="174" border="0" /></a></p>
<p style="text-align:justify;">Aceptamos los cambios, y ya estamos listos para iniciar la máquina. Al hacerlo arrancará Android, de forma muy similar a como lo hacen los AVD que se crean con el SDK:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-05-androvm-phone-ejecutndose-en-virtualbox.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="androVM Phone ejecutándose en VirtualBox" alt="androVM Phone ejecutándose en VirtualBox" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-05-androvm-phone-ejecutndose-en-virtualbox_thumb.png?w=148&#038;h=244" width="148" height="244" border="0" /></a></p>
<p style="text-align:justify;">Si no se ve la pantalla entera, podemos activar el modo ajustado, usando la tecla anfitrión (<em>Host</em>) + A. También podemos usar la misma configuración para salir de ese modo.</p>
<h3><a name="h.7v5e65buhboq"></a>Configuración de la máquina Android</h3>
<p style="text-align:justify;">Tal y como viene configurada la máquina, el renderizado gráfico se realiza por software. Para que utilice el hardware gráfico de la máquina virtual hay que ejecutar la aplicación <b>androVM Configuration</b>. Es importante comprobar que en la parte superior de la aplicación se muestre la IP que se le ha asignado a la máquina Android. Si no aparece, habrá que revisar la configuración del adaptador 1, porque algo habremos hecho mal.</p>
<p style="text-align:justify;">Para activar la aceleración hardware hay que seleccionar la opción <b>Hardware OpenGL</b> y pulsar <b>Save</b>. Nos pedirá reiniciar. Hay que pulsar <b>No</b>. Luego apagamos la máquina (desde el botón de cerrar de la ventana Windows en la que se ejecuta). <em><strong>Nota</strong>: Enviar la señal de apagado no sirve de nada, hay que apagarla</em>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-06-configuracin-de-androvm-phone.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="Configuración de androVM Phone" alt="Configuración de androVM Phone" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-06-configuracin-de-androvm-phone_thumb.png?w=148&#038;h=244" width="148" height="244" border="0" /></a></p>
<h3><a name="h.tvcousi58l3w"></a>Configuración de AndroVM PLayer</h3>
<p style="text-align:justify;">Ahora hay que configurar AndroVM Player. Al ejecutarlo se muestra la siguiente ventana:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-07-androvm-player-primer-arranque.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player - Primer arranque" alt="AndroVM Player - Primer arranque" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-07-androvm-player-primer-arranque_thumb.png?w=244&#038;h=175" width="244" height="175" border="0" /></a></p>
<p style="text-align:justify;">La aplicación permite escoger las dimensiones y la densidad de píxeles de la máquina Android, bien seleccionando una configuración típica o bien introduciendo los datos manualmente. En la parte inferior hay otra lista desplegable para escoger la máquina virtual que queremos iniciar.</p>
<p style="text-align:justify;">Si la aplicación no ha sido capaz de localizar la carpeta donde está instalado VirtualBox, tendremos que indicárselo nosotros. Para ello pulsamos el botón <b>Settings</b> de la esquina inferior derecha.</p>
<p style="text-align:justify;">En la ventana de opciones tenemos que seleccionar el ejecutable VBoxManage.exe, que se encuentra en la carpeta de VirtualBox (de forma predeterminada, C:/Archivos de programa/Oracle/VirtualBox/). Pulsamos el botón <b>Browse</b> y lo localizamos.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-08-androvm-player-settings.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player Settings" alt="AndroVM Player Settings" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-08-androvm-player-settings_thumb.png?w=244&#038;h=110" width="244" height="110" border="0" /></a></p>
<p style="text-align:justify;">También podemos escoger si queremos que la máquina virtual se ejecute dentro de una ventana de VirtualBox (<b>In a GUI</b>) o no (<b>Headless</b>). Lo mejor es escoger <b>Headless</b>, dado que la pantalla de la máquina Android se verá dentro de la aplicación AndroVM Player, por lo que no necesitamos tener también la ventana de VirtualBox.</p>
<p style="text-align:justify;">Cerramos la ventana de opciones y cerramos también la aplicación AndroVM Player si sigue indicando que no encuentra VBoxManage. Al abrirla de nuevo debería haber desaparecido el mensaje. Ya podemos seleccionar la resolución y la máquina virtual en las listas desplegables:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-09-androvm-player-conectado-a-virtualbox.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player - Conectado a VirtualBox" alt="AndroVM Player - Conectado a VirtualBox" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-09-androvm-player-conectado-a-virtualbox_thumb.png?w=244&#038;h=175" width="244" height="175" border="0" /></a></p>
<h3><a name="h.710z9xg5ap7v"></a>Ejecución desde AndroVM Player</h3>
<p style="text-align:justify;">Para ejecutar la máquina virtual hay que pulsar el botón <b>Run</b>. Si nos hemos saltado algunos pasos y no hemos activado la aceleración gráfica, AndroVM Player se dará cuenta y nos ofrecerá la opción de activarla por nosotros:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-10-androvm-player-activar-aceleracin-hardware.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player - Activar aceleración hardware" alt="AndroVM Player - Activar aceleración hardware" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-10-androvm-player-activar-aceleracin-hardware_thumb.png?w=244&#038;h=68" width="244" height="68" border="0" /></a></p>
<p style="text-align:justify;">Pulsamos <b>Enable hardware acceleration</b> para continuar. Si tampoco tenemos VirtualBox correctamente configurado, nos saldrá otro aviso:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-11-androvm-player-configurar-virtualbox.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player - Configurar VirtualBox" alt="AndroVM Player - Configurar VirtualBox" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-11-androvm-player-configurar-virtualbox_thumb.png?w=244&#038;h=68" width="244" height="68" border="0" /></a></p>
<p style="text-align:justify;">Ahora tenemos que pulsar <b>Setup VirtualBox</b>. Si no tenemos un adaptador sólo-anfitrión creado, AndroVM Player lo creará por nosotros. Dependiendo de la versión de Windows, puede que se nos soliciten credenciales de administración (incluso varias veces). Si es el caso, se las otorgamos y seguimos.</p>
<blockquote><p><em><strong>Nota</strong></em></p>
<p style="text-align:justify;"><em>Las credenciales son necesarias para crear un adaptador de red virtual en Windows. El interfaz es necesario para hacer de puente entre el equipo real y la red virtual que VirtualBox crea para las máquinas.</em></p>
</blockquote>
<p style="text-align:justify;">La siguiente comprobación que realiza AndroVM Player es si el adaptador de red de la máquina virtual está conectado al adaptador sólo-anfitrión. Si no es así, mostrará una nueva advertencia:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-12-androvm-player-configurar-adaptador-de-red.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player - Configurar adaptador de red" alt="AndroVM Player - Configurar adaptador de red" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-12-androvm-player-configurar-adaptador-de-red_thumb.png?w=244&#038;h=68" width="244" height="68" border="0" /></a></p>
<p style="text-align:justify;">Nuevamente se ofrece a hacer el trabajo por nosotros, así que pulsamos <b>Setup Network Adapter</b> para terminar la configuración de la máquina virtual.</p>
<blockquote><p><em><strong>Nota</strong></em></p>
<p style="text-align:justify;"><em>Hay que tener en cuenta que todos estos pasos sólo hay que hacerlos la primera vez que se arranca la máquina y sólo si no la hemos configurado manualmente. Las siguientes veces, la máquina arrancará directamente.</em></p>
</blockquote>
<p style="text-align:justify;">Si todo está bien configurado la máquina virtual se ejecuta con aceleración gráfica hardware. Además, AndroVM Player proporciona una barra que incluye los botones habituales de un teléfono Android:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-13-androvm-player-en-ejecucin.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player en ejecución" alt="AndroVM Player en ejecución" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-13-androvm-player-en-ejecucin_thumb.png?w=178&#038;h=244" width="178" height="244" border="0" /></a></p>
<p style="text-align:justify;">Además de la interfaz de AndroVM Player, también podemos utilizar algunas teclas para simular algunos de los botones físicos de los terminales Android:</p>
<ul>
<li>
<p style="text-align:justify;"><b>Inicio</b>: realiza la función del botón <b>HOME</b>, que sirve para regresar al lanzador de aplicaciones.</p>
</li>
<li>
<p style="text-align:justify;"><b>ESC</b>: equivale al botón <b>ATRÁS</b>.</p>
</li>
<li>
<p style="text-align:justify;"><b>F1</b> o <b>F10</b>: botón <b>MENÚ</b>.</p>
</li>
<li>
<p style="text-align:justify;"><b>F3</b>: botón <b>BUSCAR</b>.</p>
</li>
<li>
<p style="text-align:justify;"><b>F4</b> o <b>Fin</b>: botón de encendido (<b>POWER</b>).</p>
</li>
<li>
<p style="text-align:justify;"><b>F11</b>: pasar a pantalla completa (<b>F11</b> de nuevo para volver a ventana).</p>
</li>
</ul>
<p style="text-align:justify;">Si usamos el botón de apagado de la botonera de AndroVM Player para apagar la máquina Android, se cerrará la máquina virtual, pero la aplicación AndroVM Player seguirá en ejecución. Es mejor usar el botón de cierre de la ventana AndroVM Player. Al pulsarlo se muestran dos opciones: una para cerrar la máquina virtual y la aplicación (<b>Shutdown VM and Exit</b>) y otra para cerrar sólo la aplicación dejando la máquina virtual en funcionamiento (<b>Exit</b>). Si vamos a necesitar la máquina más adelante, es mejor no cerrarla.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-14-androvm-player-apagar-mquina-virtual.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player - Apagar máquina virtual" alt="AndroVM Player - Apagar máquina virtual" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-14-androvm-player-apagar-mquina-virtual_thumb.png?w=244&#038;h=68" width="244" height="68" border="0" /></a></p>
<p style="text-align:justify;">La aplicación no da la opción de crear una instantánea de la máquina virtual para no tener que arrancarla cada vez (algo que tarda algunos minutos). Aunque podríamos crear esa instantánea desde la interfaz principal de VirtualBox, luego no podremos abrir la máquina desde AndroVM Player (da un error de estado incorrecto). Esto es debido a la aceleración hardware, cuyo estado no se puede almacenar y recuperar.</p>
<blockquote><p><em><strong>Nota</strong></em></p>
<p style="text-align:justify;"><em>A veces da algún error y dice que no puede comunicarse con la máquina. Desde la interfaz principal de VirtualBox podemos ver si la máquina ha arrancado realmente o no. Si esperamos a que esté lista y pulsamos <b>Run</b> de nuevo debería funcionar. También puede ocurrir que se muestre la interfaz de la aplicación AndroVM Player, pero con la pantalla en blanco, quedándose así indefinidamente. En este caso hay que cerrar la aplicación sin cerrar la máquina virtual y volver a ejecutarla. Si sigue sin funcionar, habrá que cerrar la máquina virtual desde VirtualBox y después volver a ejecutar AndroVM Player.</em></p>
</blockquote>
<p style="text-align:justify;">Ni que decir tiene que la versión tableta se configura exactamente de la misma forma (la resolución mínima para que se active la interfaz de tabletas es 1024&#215;768):</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-15-androvm-player-tableta.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="AndroVM Player - Tableta" alt="AndroVM Player - Tableta" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-15-androvm-player-tableta_thumb.png?w=244&#038;h=149" width="244" height="149" border="0" /></a></p>
<h3><a name="h.wi7vmfl6u043"></a>Enlace de la máquina Android con el SDK</h3>
<p style="text-align:justify;">Para poder usar la máquina para desarrollar, tenemos que conectarla al PC. Para ello hay que usar la línea de comandos y ejecutar</p>
<div class="wlWriterEditableSmartContent" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:68e6742a-3785-4d95-8905-64ece8a430c8" style="float:none;margin:0;display:inline;padding:0;">
<pre class="brush: plain; gutter: false; pad-line-numbers: true; title: ; notranslate">
adb connect &lt;IP&gt;
</pre>
</div>
<p style="text-align:justify;">donde <code>&lt;IP&gt;</code> es la IP de la máquina virtual. La IP se muestra en la ventana junto al nombre de la aplicación AndroVM Player (si no lo vemos en la propia ventana, podemos dejar el cursor del ratón sobre el icono de la barra de tareas para que se muestre completo).</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-16-conexin-con-el-adb.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border-width:0;" title="Conexión con el ADB" alt="Conexión con el ADB" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-16-conexin-con-el-adb_thumb.png?w=244&#038;h=125" width="244" height="125" border="0" /></a></p>
<p style="text-align:justify;">Podemos comprobar que la máquina se ha conectado con el comando <code>adb devices</code>. Si se muestra la IP de la máquina junto a la etiqueta <code>device</code>, todo estará listo para ejecutar nuestras aplicaciones. A partir de aquí funciona como un AVD o como un dispositivo real conectado al PC.</p>
<h3><a name="h.eufb8n4do3co"></a>Compartir archivos</h3>
<p style="text-align:justify;">AndroVM Player proporciona acceso de forma automática a las carpetas que se <a href="https://columna80.wordpress.com/2010/09/12/mquinas-virtuales-vii-compartir-carpetas/" target="_blank">comparten</a> con la máquina virtual desde VirtualBox si se marcan para que se monten automáticamente.</p>
<p style="text-align:justify;">Para compartir una carpeta en VirtualBox hay que abrir la configuración de la máquina virtual Android y seleccionar <b>Carpetas compartidas</b> en el menú lateral:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-17-configuracin-de-carpetas-compartidas.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border:0;" title="Configuración de carpetas compartidas" alt="Configuración de carpetas compartidas" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-17-configuracin-de-carpetas-compartidas_thumb.png?w=244&#038;h=174" width="244" height="174" border="0" /></a></p>
<p style="text-align:justify;">Añadimos una nueva carpeta pulsando en el botón <b>Agregar carpeta compartida</b> (el que tiene un signo de suma de color verde). En <b>Ruta carpeta</b> hay que seleccionar la carpeta de la máquina anfitriona que queremos compartir (pulsando en la flecha y seleccionando <b>Otro</b>) y en <b>Nombre carpeta</b> hay que escribir el nombre que se le asignará en la máquina virtual. Finalmente, hay que seleccionar la casilla de verificación <b>Automontar</b> (imprescindible). Pulsamos <b>Aceptar</b> para compartir la carpeta y luego otra vez <b>Aceptar</b> para cerrar las opciones.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-18-agregar-carpeta-compartida.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border:0;" title="Agregar carpeta compartida" alt="Agregar carpeta compartida" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-18-agregar-carpeta-compartida_thumb.png?w=244&#038;h=169" width="244" height="169" border="0" /></a></p>
<p style="text-align:justify;">Las carpetas configuradas de esta forma se montan en la máquina Android en la ruta /mnt/shared, por lo que podemos acceder a ellas desde cualquier explorador de archivos (la máquina AndroVM incluye <strong>Astro</strong>):</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-19-androvm-accediendo-a-la-carpeta-compartida.png" target="_blank"><img loading="lazy" style="background-image:none;float:none;padding-top:0;padding-left:0;margin:5px auto;display:block;padding-right:0;border:0;" title="AndroVM  - Accediendo a la carpeta compartida" alt="AndroVM  - Accediendo a la carpeta compartida" src="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-19-androvm-accediendo-a-la-carpeta-compartida_thumb.png?w=178&#038;h=244" width="178" height="244" border="0" /></a></p>
<h3><a name="h.tq4dq393s6dv"></a>Limitaciones</h3>
<p style="text-align:justify;">Con todo esto ya tenemos lista una máquina virtual Android con aceleración gráfica y con un rendimiento bastante superior al de los AVDs que se crean con el SDK de Android. Pero hay que tener en cuenta que tenemos algunas limitaciones respecto a estos últimos.</p>
<p style="text-align:justify;">Para empezar no tenemos un botón para rotar la pantalla, ni tampoco parece haber una combinación de teclas que permita hacerlo (como en los AVDs). Si una aplicación rota la pantalla, la máquina se rota correctamente, por lo que podemos usar una aplicación que fuerce una orientación.</p>
<p style="text-align:justify;">Otra opción es utilizar las resoluciones manuales de AndroVM Player para invertir las dimensiones y arrancar la máquina en modo apaisado. Así podremos probar las aplicaciones en ambas orientaciones.</p>
<p style="text-align:justify;">También hay que tener en cuenta que no podemos tener cualquier versión de Android. Ahora mismo la versión de AndroVM disponible es la 4.1.1, por lo que si queremos probar nuestras aplicaciones en versiones anteriores tendremos que crearnos AVDs o utilizar dispositivos reales con esas versiones (si disponemos de ellos).</p>
<p style="text-align:justify;">No obstante, aunque no podamos hacer pruebas de compatibilidad con diversas versiones, sí que podemos probar toda la funcionalidad de nuestra aplicación en una de las versiones de Android más recientes, con posibilidad de depurar y con una mejor respuesta que la que podemos tener con los AVDs. Merece la pena, ¿no?</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2013/04/28/instalacin-de-una-mquina-virtual-android/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">906</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-01-configuracin-de-red-de-virtualbox_thumb.png" medium="image">
			<media:title type="html">Configuración de red de VirtualBox</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-02-detalles-de-red-slo-anfitrin-adaptador_thumb.png" medium="image">
			<media:title type="html">Detalles de red sólo-anfitrión - Adaptador</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-03-detalles-de-red-slo-anfitrin-servidor-dhcp_thumb.png" medium="image">
			<media:title type="html">Detalles de red sólo-anfitrión - Servidor DHCP</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-04-confiuracin-de-red-de-androvm-en-virtualbox_thumb.png" medium="image">
			<media:title type="html">Confiuración de red de androVM en VirtualBox</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-05-androvm-phone-ejecutndose-en-virtualbox_thumb.png" medium="image">
			<media:title type="html">androVM Phone ejecutándose en VirtualBox</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-06-configuracin-de-androvm-phone_thumb.png" medium="image">
			<media:title type="html">Configuración de androVM Phone</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-07-androvm-player-primer-arranque_thumb.png" medium="image">
			<media:title type="html">AndroVM Player - Primer arranque</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-08-androvm-player-settings_thumb.png" medium="image">
			<media:title type="html">AndroVM Player Settings</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-09-androvm-player-conectado-a-virtualbox_thumb.png" medium="image">
			<media:title type="html">AndroVM Player - Conectado a VirtualBox</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-10-androvm-player-activar-aceleracin-hardware_thumb.png" medium="image">
			<media:title type="html">AndroVM Player - Activar aceleración hardware</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-11-androvm-player-configurar-virtualbox_thumb.png" medium="image">
			<media:title type="html">AndroVM Player - Configurar VirtualBox</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-12-androvm-player-configurar-adaptador-de-red_thumb.png" medium="image">
			<media:title type="html">AndroVM Player - Configurar adaptador de red</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-13-androvm-player-en-ejecucin_thumb.png" medium="image">
			<media:title type="html">AndroVM Player en ejecución</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-14-androvm-player-apagar-mquina-virtual_thumb.png" medium="image">
			<media:title type="html">AndroVM Player - Apagar máquina virtual</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-15-androvm-player-tableta_thumb.png" medium="image">
			<media:title type="html">AndroVM Player - Tableta</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-16-conexin-con-el-adb_thumb.png" medium="image">
			<media:title type="html">Conexión con el ADB</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-17-configuracin-de-carpetas-compartidas_thumb.png" medium="image">
			<media:title type="html">Configuración de carpetas compartidas</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-18-agregar-carpeta-compartida_thumb.png" medium="image">
			<media:title type="html">Agregar carpeta compartida</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2013/04/0037-19-androvm-accediendo-a-la-carpeta-compartida_thumb.png" medium="image">
			<media:title type="html">AndroVM  - Accediendo a la carpeta compartida</media:title>
		</media:content>
	</item>
		<item>
		<title>Dise&#241;os Android b&#225;sicos: TableLayout</title>
		<link>https://columna80.wordpress.com/2012/11/05/diseos-android-bsicos-tablelayout/</link>
					<comments>https://columna80.wordpress.com/2012/11/05/diseos-android-bsicos-tablelayout/#comments</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Mon, 05 Nov 2012 18:27:07 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=841</guid>

					<description><![CDATA[Vamos a seguir avanzando en la creación de interfaces de usuario en Android, viendo otro de los diseños básicos que tenemos a nuestra disposición. Hasta ahora hemos visto diseños que permiten colocar vistas unas sobre otra o disponerlas en serie, una a continuación de otra, en horizontal o vertical. Con TableLayout añadimos una nueva dimensión, [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;">Vamos a seguir avanzando en la creación de interfaces de usuario en Android, viendo otro de los diseños básicos que tenemos a nuestra disposición. Hasta ahora hemos visto diseños que permiten colocar vistas unas sobre otra o disponerlas en serie, una a continuación de otra, en horizontal o vertical. Con <b>TableLayout</b> añadimos una nueva dimensión, pudiendo disponer las vistas tanto verticalmente como horizontalmente, en forma de tabla.</p>
<p style="text-align:justify;">Es necesario aclarar que no es el único diseño que permite esta distribución. Recientemente se ha añadido un nuevo diseño, <b>GridLayout</b>, que también permite distribuir las vistas en forma de tabla. Está disponible desde la versión 14 de la API de Android, que se corresponde con la versión 4.0 del sistema operativo (Ice Cream Sandwich), y es bastante más potente que <b>TableLayout</b>.</p>
<p style="text-align:justify;">Por el momento, dado que usar <b>GridLayout</b> impide que la aplicación funcione en versiones anteriores, vamos a centrarnos en ver cómo se utiliza <b>TableLayout</b> y ya hablaremos de <b>GridLayout</b> más adelante.</p>
<p style="text-align:justify;"><span id="more-841"></span>Lo primero que es necesario destacar de <b>TableLayout</b> es que no tiene, estrictamente hablando, una estructura de tabla. En realidad, <b>TableLayout</b> es una especialización de <b>LinearLayout</b>. En concreto, de un <a title="Diseños Android básicos: LinearLayout" href="https://columna80.wordpress.com/2012/09/15/diseos-android-bsicos-linearlayout/"><b>LinearLayout</b></a> vertical. Aunque con un comportamiento particularizado.</p>
<p style="text-align:justify;">Al igual que en un <b>LinearLayout</b>, en un <b>TableLayout</b> se pueden incluir todo tipo de vistas. Sin embargo, hay una vista específica que sólo se puede utilizar en <b>TableLayout</b> y que es la que aporta la funcionalidad necesaria para crear la tabla: <b>TableRow</b>.</p>
<p style="text-align:justify;"><b>TableRow</b> es, a su vez, otra especialización de <b>LinearLayout</b>. Esta vez de un <b>LinearLayout</b> horizontal. Así que resulta evidente que, lo que se nos vende como una estructura de tabla, es en realidad un grupo de <b>LinearLayout</b> horizontales dentro de un <b>LinearLayout</b> vertical.</p>
<p style="text-align:justify;">Esta organización tampoco resulta tan extraña. De hecho, es muy similar a la de las tablas en HTML, con las que este diseño comparte otras características, como veremos a continuación.</p>
<p style="text-align:justify;">Resulta evidente que cada <b>TableRow</b> representa una fila de la tabla y que las vistas que contengan harán las veces de columnas. En concreto, cada vista que se añade a un <b>TableRow</b> va a parar a una columna diferente. Por ese motivo se suele decir que cada celda de un <b>TableLayout</b> sólo puede contener una vista. No obstante, nada impide que cualquiera de esas vistas sea un diseño y que contenga, a su vez otras vistas dentro.</p>
<p style="text-align:justify;">Lo que diferencia a <b>TableLayout</b> de una estructura similar creada con varios <b>LinearLayout</b> es el tratamiento global que le da a las vistas que se incluyen en todos los <b>TableRow</b>. Para empezar, aunque cada <b>TableRow</b> tenga una cantidad diferente de vistas en su interior, el conjunto se representará como una tabla donde todas las filas tienen el mismo número de columnas. La cantidad total de columnas que tendrá la tabla la determina el <b>TableRow</b> que más vistas incluya. De forma similar, el ancho de cada columna también vendrá determinado por la vista con mayor anchura de todas las incluidas en esa columna, aún estando en diferentes <b>TableRow</b>.</p>
<h3>Propiedades del diseño</h3>
<p style="text-align:justify;"><b>TableLayout</b> hereda directamente de <b>LinearLayout</b>, por lo que dispone de todas sus propiedades. Aunque algunas, como <b>android:orientation</b>, carecen de efecto si se intentan usar aquí.</p>
<p style="text-align:justify;">Por su parte, <b>TableLayout</b> tiene algunas propiedades exclusivas:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><b>android:collapseColumns</b> (<b>setColumnCollapsed</b>): permite ocultar columnas, como si no estuvieran en el diseño. El espacio que dejan lo ocupan el resto de columnas.<br />
La atributo XML (<b>android:collapseColumns</b>) permite ocultar más de una columna, indicando sus índices separados por comas. Por el contrario, el método (<b>setColumnCollapsed</b>) sólo permite ocultar o mostrar una columna cada vez, pasándole como parámetros el índice de la columna y un booleano que indica si la columna debe ocultarse (<b><code>true</code></b>) o mostrarse (<b><code>false</code></b>). En ambos casos el índice de la primera columna es el cero.<br />
En la siguientes capturas se muestra un <b>TableLayout</b> con tres columnas. En la primera se muestran las tres y en la segunda se ha ocultado la de índice 1 (la segunda):</p>
<p style="text-align:center;"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-01-tablelayout-con-tres-columnas.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.01 - TableLayout con tres columnas" alt="0036.01 - TableLayout con tres columnas" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-01-tablelayout-con-tres-columnas_thumb.png?w=244&#038;h=154" height="154" width="244" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-02-tablelayout-con-una-columna-oculta.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.02 - TableLayout con una columna oculta" alt="0036.02 - TableLayout con una columna oculta" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-02-tablelayout-con-una-columna-oculta_thumb.png?w=244&#038;h=154" height="154" width="244" /></a></p>
</li>
<li>
<p style="text-align:justify;"><b>android:shrinkColumns</b> (<b>setColumnShrinkable</b>): permite marcar una o más columnas como <i>encogibles</i>, de forma que su anchura se pueda reducir para adaptarse al tamaño del contenedor del <b>TableLayout</b>.<br />
Los parámetros tanto del atributo como del método son iguales a los de la propiedad anterior, pero aquí se añade también el valor <b><code>"*"</code></b>, que permite marcar todas las columnas del <b>TableLayout</b>. Además, también disponemos del método <b>setShrinkAllColumns</b>, que permite marcar todas las columnas de la tabla como encogibles con una sola llamada.<br />
En las siguientes capturas se muestra un <b>TableLayout</b> con una celda de bastante anchura. En la segunda captura se ha marcado esa columna como encogible, de forma que quepan todas en la pantalla. Se pueden usar las propiedades del <b>TextView</b>, como veremos en un futuro post, para evitar que aumente la altura de la fila y, en su lugar, se recorte el texto (como se muestra en la tercera captura). En este caso se ha usado <b><code>android:lines="1" android:scrollHorizontally="true" android:ellipsize="end"</code></b>.</p>
<p style="text-align:center;"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-03-columna-muy-grande.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.03 - Columna muy grande" alt="0036.03 - Columna muy grande" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-03-columna-muy-grande_thumb.png?w=244&#038;h=184" height="184" width="244" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-04-columna-encogida.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.04 - Columna encogida" alt="0036.04 - Columna encogida" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-04-columna-encogida_thumb.png?w=244&#038;h=184" height="184" width="244" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-05-columna-encogida-y-texto-recortado.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.05 - Columna encogida y texto recortado" alt="0036.05 - Columna encogida y texto recortado" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-05-columna-encogida-y-texto-recortado_thumb.png?w=244&#038;h=184" height="184" width="244" /></a></p>
</li>
<li>
<p style="text-align:justify;"><b>android:stretchColumns</b> (<b>setColumnStretchable</b>): esta propiedad viene a ser la opuesta de la anterior, dado que permite que una columna se expanda aumentando su anchura hasta que todo el contenido del <b>TableLayout</b> ocupe la totalidad de la anchura de su contenedor.<br />
Los parámetros que toma son iguales que los de las propiedades anteriores, incluyendo el valor especial <b><code>"*"</code></b>, para expandir todas las columnas. Además, aquí también disponemos de un método, <b>setStretchAllColumns</b>, que también permite marcar todas las columnas como expandibles de una vez.<br />
En las siguientes capturas se muestra un <b>TableLayout</b> con tres columnas, primero sin marcar ninguna como expandible, después marcando la de índice 2 (la tercera) y, finalmente, marcando la 0 y la 2:</p>
<p style="text-align:center;"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-01-tablelayout-con-tres-columnas1.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.01 - TableLayout con tres columnas" alt="0036.01 - TableLayout con tres columnas" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-01-tablelayout-con-tres-columnas_thumb1.png?w=244&#038;h=147" height="147" width="244" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-06-columna-expandida.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.06 - Columna expandida" alt="0036.06 - Columna expandida" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-06-columna-expandida_thumb.png?w=244&#038;h=147" height="147" width="244" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-07-dos-columnas-expandidas.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.07 - Dos columnas expandidas" alt="0036.07 - Dos columnas expandidas" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-07-dos-columnas-expandidas_thumb.png?w=244&#038;h=147" height="147" width="244" /></a></p>
</li>
</ul>
</div>
<p style="text-align:justify;">Las propiedades de encoger y expandir permiten que nuestro diseño se adapte perfectamente a cualquier tamaño de pantalla, al tiempo que controlamos cuáles de las columnas pueden variar su tamaño y cuáles no. Una misma columna se puede marcar con ambas propiedades, de forma que se adapte a tamaños más pequeños o más grandes. Si las propiedades se aplican a más de una columna, el tamaño que es necesario añadir o reducir se reparte de forma equitativa entre todas ellas.</p>
<h3>Parámetros</h3>
<p style="text-align:justify;">Al igual que ocurre con las propiedades, <b>TableLayout</b> hereda también todos los parámetros de diseño de <b>LinearLayout</b>. Sin embargo, aunque existe una clase <b>TableLayout.LayoutParams</b>, no se define en ella ningún nuevo parámetro. Así que sólo disponemos de los que proporciona <b>LinearLayout</b>, y con algunas limitaciones.</p>
<p style="text-align:justify;">Por ejemplo, el parámetro <b>android:layout_width</b> de los elementos que incluyamos en un <b>TableLayout</b> siempre tendrá el valor <b><code>match_parent</code></b>, ignorando cualquier otro valor que tratemos de poner. Aunque hay que tener en cuenta que, normalmente, dentro del <b>TableLayout</b> sólo pondremos elementos de tipo <b>TableRow</b>, por lo que es normal que la anchura de estos elementos siempre iguale a la del <b>TableLayout</b>.</p>
<p style="text-align:justify;">En el caso del parámetro <b>android:layout_height</b>, también encontramos una diferencia: <b>TableLayout</b> no obliga a definirlos en los elementos que contiene (los <b>TableRow</b>). Si no se incluyen, se asume el valor <b><code>wrap_content</code></b>.</p>
<h4>Parámetros de TableRow</h4>
<p style="text-align:justify;">Como ya hemos comentado, <b>TableRow</b> es también una especialización de <b>LinearLayout</b>. Por lo tanto, es un diseño. Y como tal puede proporcionar parámetros para que se utilicen como atributos de las vistas que se incluyan en él.</p>
<p style="text-align:justify;">En concreto, la clase <b>TableRow.LayoutParams</b> proporciona dos:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><b>android:layout_column</b>: sirve para colocar la vista a la que se aplica en una columna diferente a la que le correspondería según el orden en el que se ha incluido en el <b>TableRow</b>. Hay que tener en cuenta que las columnas se numeran a partir del cero.<br />
La siguiente captura muestra el <b>TableLayout</b> de los ejemplos anteriores, pero con el valor <b><code>"2"</code></b> en el parámetro <b>android:layout_column</b> del segundo <b>TextView</b> de la filas 2 y 4, y en la primera vista de la tercera fila:</p>
<p style="text-align:center;"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-08-columnas-desplazadas.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.08 - Columnas desplazadas" alt="0036.08 - Columnas desplazadas" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-08-columnas-desplazadas_thumb.png?w=404&#038;h=152" height="152" width="404" /></a></p>
<p style="text-align:justify;">Como se puede observar, cuando nos saltamos alguna columna usando este atributo, las columnas posteriores se colocan a continuación, desplazándose también de la posición que les hubiera correspondido, e incluso aumentando el total de columnas del <b>TableLayout</b> si es necesario.<br />
Por otro lado, se ignoran los valores que son inferiores a la posición que le corresponde actualmente a la vista. En el ejemplo, hemos usado el valor <b><code>"1"</code></b> en el atributo <b>android:layout_column</b> del tercer <b>TextView</b> de la fila 3. Sin embargo, el orden de las vistas no se altera y el valor <b><code>"1"</code></b>, al ser inferior al que le corresponde a esta vista (que sería <b><code>"3"</code></b>), simplemente se ignora.</p>
</li>
<li>
<p style="text-align:justify;"><b>android:layout_span</b>: permite que una vista ocupe más de una columna. Tiene que tener un valor numérico igual o superior a <b><code>"1"</code></b>. El valor <b><code>"1"</code></b> es el predeterminado.<br />
En la siguiente captura podemos verlo en acción. En este caso hemos hecho que la primera vista de la fila 2 ocupe dos columnas y que la segunda vista de la fila 3 ocupe tres columnas, usando los valores <b><code>"2"</code></b> y <b><code>"3"</code></b>, respectivamente:</p>
<p style="text-align:center;"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-09-vistas-que-ocupan-ms-de-una-columna.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="0036.09 - Vistas que ocupan más de una columna" alt="0036.09 - Vistas que ocupan más de una columna" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-09-vistas-que-ocupan-ms-de-una-columna_thumb.png?w=404&#038;h=151" height="151" width="404" /></a></p>
<p style="text-align:justify;">Como se puede observar, aquí también se aumenta el número de columnas del <b>TableLayout</b> si es necesario.</p>
</li>
</ul>
</div>
<h3>Uso de TableLayout en XML</h3>
<p style="text-align:justify;">Veamos ahora un ejemplo de actividad cuyo diseño principal es un <b>TableLayout</b>:</p>
<p style="text-align:center;"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-10-ejemplo-de-tablelayout.png" target="_blank"><img loading="lazy" class="aligncenter" style="background-image:none;margin-top:5px;margin-bottom:5px;padding-left:0;padding-right:0;display:block;padding-top:0;border-width:0;" title="0036.10 - Ejemplo de TableLayout" alt="0036.10 - Ejemplo de TableLayout" src="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-10-ejemplo-de-tablelayout_thumb.png?w=404&#038;h=172" height="172" width="404" /></a></p>
<p>El código XML que permite crear esta tabla es el siguiente:</p>
<pre class="brush: xml; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;TableLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:id=&quot;@+id/Tabla&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:stretchColumns=&quot;1&quot; &gt;

    &lt;TableRow
        android:id=&quot;@+id/Cabecera&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;TextView
            android:id=&quot;@+id/ColumnaAnio&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:padding=&quot;5px&quot;
            android:text=&quot;Año&quot;
            android:textColor=&quot;#005500&quot;
            android:textSize=&quot;26sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/ColumnaCiudad&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_gravity=&quot;center_horizontal&quot;
            android:padding=&quot;5px&quot;
            android:text=&quot;Ciudad&quot;
            android:textColor=&quot;#005500&quot;
            android:textSize=&quot;26sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/ColumnaOro&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:padding=&quot;5px&quot;
            android:text=&quot;Oro&quot;
            android:textColor=&quot;#005500&quot;
            android:textSize=&quot;26sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/ColumnaPlata&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:padding=&quot;5px&quot;
            android:text=&quot;Plata&quot;
            android:textColor=&quot;#005500&quot;
            android:textSize=&quot;26sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/ColumnaBronce&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:padding=&quot;5px&quot;
            android:text=&quot;Bronce&quot;
            android:textColor=&quot;#005500&quot;
            android:textSize=&quot;26sp&quot; /&gt;
    &lt;/TableRow&gt;

    &lt;TableRow
        android:id=&quot;@+id/SeparadorCabecera&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;FrameLayout
            android:id=&quot;@+id/LineaCabecera&quot;
            android:layout_width=&quot;fill_parent&quot;
            android:layout_height=&quot;2px&quot;
            android:layout_span=&quot;6&quot;
            android:background=&quot;#FFFFFF&quot; &gt;
        &lt;/FrameLayout&gt;
    &lt;/TableRow&gt;

    &lt;TableRow
        android:id=&quot;@+id/Fila1&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;TextView
            android:id=&quot;@+id/Anio1&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;1900&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Cuidad1&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;París&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Oro1&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;1&quot;
            android:textSize=&quot;20sp&quot; /&gt;
    &lt;/TableRow&gt;

    &lt;TableRow
        android:id=&quot;@+id/Fila2&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;TextView
            android:id=&quot;@+id/Anio2&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;1976&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Cuidad2&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;Montreal&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Plata2&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_column=&quot;3&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;2&quot;
            android:textSize=&quot;20sp&quot; /&gt;
    &lt;/TableRow&gt;

    &lt;TableRow
        android:id=&quot;@+id/Fila3&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;TextView
            android:id=&quot;@+id/Anio3&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;1992&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Cuidad3&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;Barcelona&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Oro3&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;13&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Plata3&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;7&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Bronce3&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;2&quot;
            android:textSize=&quot;20sp&quot; /&gt;
    &lt;/TableRow&gt;

    &lt;TableRow
        android:id=&quot;@+id/Fila4&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;TextView
            android:id=&quot;@+id/Anio4&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;2012&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Cuidad4&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;Londres&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Oro4&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;3&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Plata4&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;10&quot;
            android:textSize=&quot;20sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/Bronce4&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;4&quot;
            android:textSize=&quot;20sp&quot; /&gt;
    &lt;/TableRow&gt;

    &lt;TableRow
        android:id=&quot;@+id/SeparadorTotales&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;FrameLayout
            android:id=&quot;@+id/LineaTotales&quot;
            android:layout_width=&quot;fill_parent&quot;
            android:layout_height=&quot;2px&quot;
            android:layout_span=&quot;5&quot;
            android:background=&quot;#FFFFFF&quot; &gt;
        &lt;/FrameLayout&gt;
    &lt;/TableRow&gt;

    &lt;TableRow
        android:id=&quot;@+id/Totales&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot; &gt;

        &lt;TextView
            android:id=&quot;@+id/TextoTotal&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_span=&quot;2&quot;
            android:gravity=&quot;right&quot;
            android:text=&quot;Total&quot;
            android:textColor=&quot;#0000CC&quot;
            android:textSize=&quot;22sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/OroTotal&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;17&quot;
            android:textSize=&quot;22sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/PlataTotal&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;19&quot;
            android:textSize=&quot;22sp&quot; /&gt;

        &lt;TextView
            android:id=&quot;@+id/BronceTotal&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:gravity=&quot;center&quot;
            android:text=&quot;6&quot;
            android:textSize=&quot;22sp&quot; /&gt;
    &lt;/TableRow&gt;

&lt;/TableLayout&gt;

</pre>
<p style="text-align:justify;">Como se puede observar, la actividad contiene un único <b>TableLayout</b> que ocupa todo su espacio visible. Dentro del <b>TableLayout</b> se incluyen únicamente diseños <b>TableRow</b>, uno por cada fila. Y dentro de los <b>TableRow</b> se incluyen diversos <b>TextView</b>, con las cadenas de texto que se muestran en cada celda de la tabla.</p>
<p style="text-align:justify;">La única excepción son los <b>TableRow</b> que se utilizan para las líneas separadoras (la que separa la cabecera de la tabla y la que separa la fila de totales). En estos <b>TableRow</b> se ha incluido un <a title="Diseños Android básicos: FrameLayout" href="https://columna80.wordpress.com/2012/08/22/diseos-android-bsicos-framelayout/"><b>FrameLayout</b></a> con una altura muy pequeña (2 píxeles) y con el fondo de color blanco.</p>
<p style="text-align:justify;">Es una forma sencilla de crear líneas y se utiliza con frecuencia con todo tipo de diseños, no únicamente con <b>TableLayout</b>. Esto se debe a que, a diferencia de otros entornos, en Android los widgets no tienen propiedades específicas para los bordes. No podemos definir, como, por ejemplo, en HTML, el ancho, color y estilo de cada borde simplemente asignando valores a propiedades.</p>
<p style="text-align:justify;">Esto no quiere decir que no se puedan mostrar bordes en las celdas de un <b>TableLayout</b>, sino que hacerlo resulta un poco más complejo de lo que cabría suponer. En Android los bordes forman parte de la imagen gráfica del widget, la cual se puede modificar mediante un tipo de recursos llamados dibujables (<i>drawables</i>). De estos recursos hablaremos en un futuro post.</p>
<p style="text-align:justify;">Además de usar un <b>FrameLayout</b> para crear líneas, también podemos jugar con los colores de fondo del <b>TableRow</b> y el de los widgets de las celdas, junto con el <a title="Diseñando interfaces en Android: padding y margen" href="https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/">padding</a>, para simular los bordes. Aunque de esta forma las opciones de personalización son algo menores.</p>
<h3>Ejemplo en Java</h3>
<p style="text-align:justify;">Como ya es habitual, ahora veremos la forma de crear la misma interfaz de usuario mediante código Java:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:097b2846-3442-425a-b64f-67f2f36ddbcf" class="wlWriterEditableSmartContent">
<pre class="brush: java; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Datos para la tabla
        String cabeceras[] = { &quot;Año&quot;, &quot;Ciudad&quot;, &quot;Oro&quot;, &quot;Plata&quot;, &quot;Bronce&quot; };
        String datos[][] = { { &quot;1900&quot;, &quot;París&quot;, &quot;1&quot;, &quot;&quot;, &quot;&quot; },
                             { &quot;1976&quot;, &quot;Montreal&quot;, &quot;&quot;, &quot;2&quot;, &quot;&quot; },
                             { &quot;1992&quot;, &quot;Barcelona&quot;, &quot;13&quot;, &quot;7&quot;, &quot;2&quot; },
                             { &quot;2012&quot;, &quot;Londres&quot;, &quot;3&quot;, &quot;10&quot;, &quot;4&quot; } };

        // TableLayout (diseño principal de la actividad)
        TableLayout tabla = new TableLayout(this);
        tabla.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tabla.setColumnStretchable(1, true);

        // Cabecera de la tabla
        TableRow cabecera = new TableRow(this);
        cabecera.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        tabla.addView(cabecera);

        // Textos de la cabecera
        for (int i = 0; i &lt; 5; i++)
        {
           TextView columna = new TextView(this);
           columna.setLayoutParams(new TableRow.LayoutParams(
              LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
           columna.setText(cabeceras[i]);
           columna.setTextColor(Color.parseColor(&quot;#005500&quot;));
           columna.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26);
           columna.setGravity(Gravity.CENTER_HORIZONTAL);
           columna.setPadding(5, 5, 5, 5);
           cabecera.addView(columna);
        }

        // Línea que separa la cabecera de los datos
        TableRow separador_cabecera = new TableRow(this);
        separador_cabecera.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        FrameLayout linea_cabecera = new FrameLayout(this);
        TableRow.LayoutParams linea_cabecera_params =
           new TableRow.LayoutParams(LayoutParams.FILL_PARENT, 2);
        linea_cabecera_params.span = 6;
        linea_cabecera.setBackgroundColor(Color.parseColor(&quot;#FFFFFF&quot;));
        separador_cabecera.addView(linea_cabecera, linea_cabecera_params);
        tabla.addView(separador_cabecera);

        // Array para los totales
        int valores_totales[] = { 0, 0, 0 };

        // Filas de datos
        for (int f = 0; f &lt; 4; f++)
        {
           TableRow fila = new TableRow(this);

           for (int c = 0; c = 2) valores_totales[c-2] += Integer.parseInt(datos[f][c]);
              }
           }

           tabla.addView(fila);
        }

        // Línea que separa los datos de la fila de totales
        TableRow separador_totales = new TableRow(this);
        separador_totales.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        FrameLayout linea_totales = new FrameLayout(this);
        TableRow.LayoutParams linea_totales_params =
           new TableRow.LayoutParams(LayoutParams.FILL_PARENT, 2);
        linea_totales_params.span = 6;
        linea_totales.setBackgroundColor(Color.parseColor(&quot;#FFFFFF&quot;));
        separador_totales.addView(linea_totales, linea_totales_params);
        tabla.addView(separador_totales);

        // Fila de totales
        TableRow totales = new TableRow(this);
        totales.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

        TextView texto_total = new TextView(this);
        TableRow.LayoutParams texto_total_params =
           new TableRow.LayoutParams(
              LayoutParams.WRAP_CONTENT,
              LayoutParams.WRAP_CONTENT);
        texto_total_params.span = 2;
        texto_total.setText(&quot;Total&quot;);
        texto_total.setTextColor(Color.parseColor(&quot;#0000CC&quot;));
        texto_total.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22);
        texto_total.setGravity(Gravity.RIGHT);
        totales.addView(texto_total, texto_total_params);

        for (int i = 0; i &lt; 3; i++)
        {
           TextView columna = new TextView(this);
           columna.setLayoutParams(new TableRow.LayoutParams(
              LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
           columna.setText(String.valueOf(valores_totales[i]));
           columna.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22);
           columna.setGravity(Gravity.CENTER);
           totales.addView(columna);
        }

        tabla.addView(totales);

        // Añadimos la tabla a la actividad
        setContentView(tabla);
    }
</pre>
</div>
<p style="text-align:justify;">En este caso me he creado varios arrays con la información que tiene que mostrarse en la tabla. Los recorro mediante bucles <b><code>for</code></b>, dentro de los cuales voy creando un widget para cada cadena de texto a mostrar. Además, los totales los calculo a medida que voy añadiendo las filas de datos, guardándolos en otro array para mostrarlos después en la última fila de la tabla.</p>
<p style="text-align:justify;">En las filas de datos, las cadenas vacías las ignoro, pero cada widget lo asocio a la columna que le corresponde para que se coloque en su sitio, dejando columnas vacías si es necesario. Esto se hace mediante el atributo público <b>column</b> de la clase <b>TableRow.LayoutParams</b>.</p>
<p style="text-align:justify;">Esta clase no dispone de un constructor que permita definir al ancho y alto del widget y, al mismo tiempo, asociarlo a una columna. Así que primero tenemos que crear el objeto, luego asignar el número de columna al atributo <b>column</b> y después asociarle el objeto con los parámetros al widget al incluirlo en el <b>TableRow</b> (en la llamada a <b>addView</b>).</p>
<p style="text-align:justify;">Con el parámetro <b>android:layout_span</b> que necesitamos para que los <b>FrameLayout</b> que crean las líneas horizontales ocupen todo el ancho del <b>TableLayout</b> hay que hacer lo mismo: crear un objeto <b>TableRow.LayoutParams</b>, asignar el número de columnas a ocupar al atributo público <b>span</b> y asociar los parámetros al widget al llamar a <b>addView</b> para agregarlo al <b>TableRow</b>.</p>
<p style="text-align:justify;">Por último, un detalle importante a tener en cuenta: si se va a crear un objeto <b>LayoutParams</b> para un <b>TableRow</b>, debe ser siempre de la clase <b>TableRow.LayoutParams</b>, aunque sólo se vaya a definir ancho y alto y no sea necesario utilizar ninguno de los parámetros propios del <b>TableRow</b>. Si usamos un objeto de la clase <b>ViewGroup.LayoutParams</b> el <b>TableRow</b> podría incluso no mostrarse en la actividad.</p>
<p class="sticky" style="text-align:center;">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2012/11/05/diseos-android-bsicos-tablelayout/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">841</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-01-tablelayout-con-tres-columnas_thumb.png" medium="image">
			<media:title type="html">0036.01 - TableLayout con tres columnas</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-02-tablelayout-con-una-columna-oculta_thumb.png" medium="image">
			<media:title type="html">0036.02 - TableLayout con una columna oculta</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-03-columna-muy-grande_thumb.png" medium="image">
			<media:title type="html">0036.03 - Columna muy grande</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-04-columna-encogida_thumb.png" medium="image">
			<media:title type="html">0036.04 - Columna encogida</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-05-columna-encogida-y-texto-recortado_thumb.png" medium="image">
			<media:title type="html">0036.05 - Columna encogida y texto recortado</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-01-tablelayout-con-tres-columnas_thumb1.png" medium="image">
			<media:title type="html">0036.01 - TableLayout con tres columnas</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-06-columna-expandida_thumb.png" medium="image">
			<media:title type="html">0036.06 - Columna expandida</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-07-dos-columnas-expandidas_thumb.png" medium="image">
			<media:title type="html">0036.07 - Dos columnas expandidas</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-08-columnas-desplazadas_thumb.png" medium="image">
			<media:title type="html">0036.08 - Columnas desplazadas</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-09-vistas-que-ocupan-ms-de-una-columna_thumb.png" medium="image">
			<media:title type="html">0036.09 - Vistas que ocupan más de una columna</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/11/0036-10-ejemplo-de-tablelayout_thumb.png" medium="image">
			<media:title type="html">0036.10 - Ejemplo de TableLayout</media:title>
		</media:content>
	</item>
		<item>
		<title>Dise&#241;os Android b&#225;sicos: LinearLayout</title>
		<link>https://columna80.wordpress.com/2012/09/15/diseos-android-bsicos-linearlayout/</link>
					<comments>https://columna80.wordpress.com/2012/09/15/diseos-android-bsicos-linearlayout/#comments</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Sat, 15 Sep 2012 12:07:51 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=811</guid>

					<description><![CDATA[LinearLayout es otro de los diseños básicos con que contamos en Android para crear las interfaces de usuario de nuestras aplicaciones. A diferencia de FrameLayout, que coloca cada vista que se incluye en él sobre la anterior, LinearLayout coloca las vistas una a continuación de otra, sin superponerlas nunca. Es decir, las alinea. Esta alineación [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;" align="justify"><strong>LinearLayout</strong> es otro de los diseños básicos con que contamos en Android para crear las interfaces de usuario de nuestras aplicaciones. A diferencia de <strong><a href="https://columna80.wordpress.com/2012/08/22/diseos-android-bsicos-framelayout/">FrameLayout</a></strong>, que coloca cada vista que se incluye en él sobre la anterior, <strong>LinearLayout</strong> coloca las vistas una a continuación de otra, sin superponerlas nunca. Es decir, las alinea.</p>
<p style="text-align:justify;" align="justify">Esta alineación puede ser vertical u horizontal. O sea, que <strong>LinearLayout</strong> sirve para colocar vistas en una misma fila o columna, pero no ambas cosas a la vez.</p>
<p style="text-align:justify;" align="justify">Las vistas se colocan en el mismo orden en se agregan al diseño o en el que aparecen en el archivo XML.</p>
<p style="text-align:justify;" align="justify">De forma predeterminada, <strong>LinearLayout</strong> tiende a establecer el mismo tamaño para cada vista que contiene, repartiendo el espacio disponible de forma equitativa entre todas ellas. Sin embargo, algunas propiedades de las vistas y ciertos parámetros que el propio <strong>LinearLayout</strong> añade permiten variar este comportamiento.</p>
<p style="text-align:justify;" align="justify">Veamos cómo sacarle partido a este diseño.</p>
<p><span id="more-811"></span></p>
<h3 align="justify">Propiedades</h3>
<p style="text-align:justify;" align="justify">Comencemos por algunas de las propiedades que tiene <strong>LinearLayout</strong>, además de las que le aporta la clase <strong>View</strong> y que ya vimos en un <a href="https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/">post anterior</a>:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><strong>android:orientation</strong> (<strong>setOrientation</strong>): la principal propiedad de <strong>LinearLayout</strong>. Determina si las vistas se alinean verticalmente u horizontalmente. Puede tomar dos valores: <code><strong>horizontal</strong></code> o <code><strong>vertical</strong></code>. De forma predeterminada, la orientación es vertical.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:baselineAligned</strong> (<strong>setBaselineAligned</strong>): de forma predeterminada, <strong>LinearLayout</strong> alinea las vistas que contiene en función de su línea base (línea invisible sobre la que apoya el texto). Esto permite que un <strong>TextView</strong> y un <strong>Button</strong> queden alineados verticalmente de forma natural en un diseño horizontal. Sin embargo, este tipo de alineación puede dar problemas en algunos casos. Establecer esta propiedad a <code>false</code> desactiva este alineamiento. La siguiente captura muestra ambas opciones:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-01-opciones-de-baselinealigned.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px auto;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;" title="Opciones de baselineAligned" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-01-opciones-de-baselinealigned_thumb.png?w=644&#038;h=166" alt="Opciones de baselineAligned" width="644" height="166" border="0" /></a></p>
</li>
<li>
<p style="text-align:justify;"><strong>android:gravity</strong> (<strong>setGravity</strong>): permite definir la gravedad del propio <strong>LinearLayout</strong>, o sea, cómo se alinea todo su contenido. Afecta al conjunto de las vistas que se incluyen en él, pero no al contenido de las propias vistas. En la siguiente captura se ve más claro. Los valores que puede tomar son los habituales para la gravedad (los que vimos en el <a href="https://columna80.wordpress.com/2012/08/22/diseos-android-bsicos-framelayout/">post</a> de <strong>FrameLayout</strong>).</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-02-ejemplo-de-gravity.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Ejemplo de gravity" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-02-ejemplo-de-gravity_thumb.png?w=644&#038;h=105" alt="Ejemplo de gravity" width="644" height="105" border="0" /></a></p>
<p style="text-align:justify;">En la captura se muestra un <strong>LinearLayout</strong> horizontal que contiene dos <strong>TextView</strong>. El atributo <strong>android:gravity</strong> del <strong>LinearLayout</strong> tiene el valor <code><strong>center_horizontal</strong></code>, lo que provoca que las dos vistas que contienen se centren en el espacio horizontal que ocupa el diseño. Se puede ver cómo la gravedad del diseño no afecta al contenido de los <strong>TextView</strong>, que mantienen su alineación predeterminada: a la izquierda.</p>
</li>
</ul>
</div>
<h3>Parámetros de diseño</h3>
<p style="text-align:justify;" align="justify">Al igual que el resto de diseños, <strong>LinearLayout</strong> define su propia clase de parámetros de diseño, que añade propiedades a las vistas que contiene. En este caso, <strong>LinearLayout.LayourParams</strong> hereda de <strong>ViewGroup.MarginLayoutParams</strong>. Esta última clase, como ya vimos en el <a href="https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/">post sobre padding y margen</a>, hereda de <strong>ViewGroup.LayoutParams</strong> añadiendo las propiedades que permiten definir márgenes para las vistas.</p>
<p style="text-align:justify;" align="justify">Esta jerarquía de clases permite que <strong>LinearLayout.LayoutParams</strong> herede parámetros genéricos como <strong>android:layout_width</strong> y <strong>android:layout_height</strong> y, al mismo tiempo, los de los márgenes (<strong>android:layout_marginLeft</strong>, <strong>android:layout_marginTop</strong>, etc). A todos estos añade dos de cosecha propia: gravedad y peso.</p>
<h4 align="justify">Gravedad</h4>
<p style="text-align:justify;" align="justify">La gravedad (<strong>android:layout_gravity</strong>) es idéntica a la que proporciona <strong>FrameLayout</strong>, por lo que no volveré a describirla aquí. Lo que sí hay que tener en cuenta es en qué se diferencia respecto a la gravedad del propio diseño (<strong>android:gravity</strong>), comentada en el apartado anterior.</p>
<p style="text-align:justify;" align="justify">Aunque funcionan de forma muy similar, la propiedad <strong>android:gravity</strong> afecta al conjunto de todas las vistas contenidas en el diseño, mientras que el parámetro <strong>android:layout_gravity</strong> sólo afecta a la vista a la que se le asigna. Las siguientes capturas dejarán más claras las diferencias:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-03-ejemplo-de-gravity-y-layout_gravity.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Ejemplo de gravity y layout_gravity" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-03-ejemplo-de-gravity-y-layout_gravity_thumb.png?w=644&#038;h=196" alt="Ejemplo de gravity y layout_gravity" width="644" height="196" border="0" /></a></p>
<p style="text-align:justify;" align="justify">En la captura se muestra un <strong>LinearLayout</strong> horizontal con fondo rojo. Al igual que en la captura anterior, el atributo <strong>android:gravity</strong> tiene el valor <code><strong>center_horizontal</strong></code>. La diferencia es que, ahora, el segundo <strong>TextView</strong> utiliza el parámetro <strong>android:layout_gravity</strong> con el valor <code><strong>bottom</strong></code>, lo que provoca que se alinee con la parte inferior del <strong>LinearLayout</strong>. El otro <strong>TextView</strong>, al no definir ningún alineamiento, se queda en la parte superior (es el comportamiento predeterminado). Pero lo más destacable de la captura es cómo el atributo <strong>android:gravity</strong> afecta al conjunto de los dos <strong>TextView</strong> contenidos en el <strong>LinearLayout</strong>, centrándolos horizontalmente como si fueran un único elemento, en lugar de hacerlo individualmente.</p>
<p style="text-align:justify;" align="justify">Veamos ahora las dos capturas siguientes:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-04-ejemplo-de-layout_gravity-en-linearlayout-horizontal.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Ejemplo de layout_gravity en LinearLayout horizontal" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-04-ejemplo-de-layout_gravity-en-linearlayout-horizontal_thumb.png?w=644&#038;h=169" alt="Ejemplo de layout_gravity en LinearLayout horizontal" width="644" height="169" border="0" /></a><br />
<a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-05-ejemplo-de-layout_gravity-en-linearlayout-vertical.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Ejemplo de layout_gravity en LinearLayout vertical" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-05-ejemplo-de-layout_gravity-en-linearlayout-vertical_thumb.png?w=644&#038;h=167" alt="Ejemplo de layout_gravity en LinearLayout vertical" width="644" height="167" border="0" /></a></p>
<p style="text-align:justify;" align="justify">Las dos capturas muestran un <strong>LinearLayout</strong> (con fondo rojo) que contiene dos <strong>TextView</strong>. El primer <strong>TextView</strong> tiene los valores <code><strong>bottom</strong></code> y <code><strong>center_horizontal</strong></code> en el parámetro <strong>android:layout_gravity</strong>, mientras que el segundo sólo tiene el valor <code><strong>center_horizontal</strong></code> en su parámetro <strong>android:layout_gravity</strong>. En ninguna de las dos capturas se ha utilizado el atributo <strong>android:gravity</strong> del <strong>LinearLayout</strong>.</p>
<p style="text-align:justify;" align="justify">¿En qué se diferencian, entonces, los diseños de ambas capturas? Tan sólo en una cosa: la orientación del <strong>LinearLayout</strong>. En la captura superior el <strong>LinearLayout</strong> es horizontal, mientras que en la captura inferior es vertical. Esto pone de relieve una particularidad del parámetro <strong>android:layout_gravity</strong> cuando se utiliza en un <strong>LinearLayout</strong> (y que no se daba en el <strong>FrameLayout</strong>): las opciones de alineamiento que afectan a la dirección en la que se orienta el <strong>LinearLayout</strong> se ignoran.</p>
<p style="text-align:justify;" align="justify">En la primera captura, donde el <strong>LinearLayout</strong> es horizontal, se está ignorando el valor <code><strong>center_horizontal</strong></code> de ambos <strong>TextView</strong>. En la segunda captura, que muestra un <strong>LinearLayout</strong> vertical, el valor que se está ignorando es el <code><strong>bottom</strong></code> del primer <strong>TextView</strong>.</p>
<p style="text-align:justify;" align="justify">Si lo piensas tiene bastante sentido. La primera regla de un <strong>LinearLayout</strong> es que las vistas se muestran en orden secuencial, según se hayan añadido al diseño. Permitir total libertad a la hora de usar la gravedad podría alterar ese orden.</p>
<p style="text-align:justify;" align="justify">Por ejemplo, supongamos que en un <strong>LinearLayout</strong> vertical se incluyen tres vistas y se utiliza <code><strong>center_vertical</strong></code> en el parámetro <strong>android:layout_gravity</strong> de la primera y la tercera. Si el diseño tratara de centrar estas dos vistas tendría que alterar la secuencia en que fueran agregadas, colocando la segunda vista en la parte superior y a continuación, en el centro, la primera y la tercera. Como esto no está permitido, lo que se hace es ignorar esos valores de la gravedad. Lo que sí se podría hacer, en este mismo ejemplo, es aplicar la gravedad <code><strong>center_vertical</strong></code> a todo el contenido del <strong>LinearLayout</strong> usando el atributo <strong>android:gravity</strong>. En ese caso, las tres vistas quedarían centradas verticalmente, sin que se alterara el orden en el que fueron agregadas.</p>
<p style="text-align:justify;" align="justify">En la captura inferior, la que muestra un <strong>LinearLayout</strong> vertical, también se ve claramente dónde está el problema de aplicar las opciones de alineamiento en la dirección del <strong>LinearLayout</strong>: si se hiciera caso al valor <code><strong>bottom</strong></code>, el <strong>TextView</strong> con fondo verde se tendría que colocar en la parte inferior del <strong>LinearLayout</strong>, quedando debajo del <strong>TextView</strong> con fondo azul, e invirtiendo el orden en que fueron agregados ambos widgets al diseño.</p>
<h4 align="justify">Peso</h4>
<p style="text-align:justify;" align="justify">Ya hemos comentado que <strong>LinearLayout</strong>, de forma predeterminada, tiende a repartir el espacio disponible de forma uniforme entre las vistas que tiene que distribuir, asignando un tamaño similar a cada una de ellas (aunque teniendo en cuenta las restricciones que la propia vista imponga).</p>
<p style="text-align:justify;" align="justify">El peso permite variar este comportamiento, asignando a cada vista un nivel de «importancia» que se traduce en más o menos espacio ocupado en el resultado final, de forma proporcional al valor asignado. El atributo que se utiliza para ello es <strong>android:layout_weight</strong>.</p>
<p style="text-align:justify;" align="justify">Si, por ejemplo, asignamos pesos 1, 2 y 3 a tres vistas, <strong>LinearLayout</strong> tratará de asignar la mitad del espacio disponible a la que tiene peso 3 (3 es la mitad de la suma total de los pesos, que es 6 en este ejemplo). De forma similar, la otra mitad del espacio libre la repartirá entre las otras dos vistas tratando de usar el doble para la que tiene peso 2. La siguiente captura muestra esa situación:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-06-ejemplo-de-pesos.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Ejemplo de pesos" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-06-ejemplo-de-pesos_thumb.png?w=644&#038;h=81" alt="Ejemplo de pesos" width="644" height="81" border="0" /></a></p>
<p style="text-align:justify;" align="justify">Hay que tener en cuenta que el reparto no es exacto. Incluso si la vista no incluye ninguna restricción especial, como <strong>android:minWidth</strong>, su contenido puede afectar al espacio que se le asigne finalmente. Android siempre tratará de conseguir la mejor visualización posible para cada vista, aunque tenga que incumplir ligeramente alguna de las restricciones que impongamos.</p>
<p align="justify">Si no asignamos peso a una vista se supone que su peso es cero. En este caso su tamaño se determinará con las restricciones habituales, y las vistas con peso se repartirán el resto del espacio de forma proporcional a dicho peso:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-07-ejemplo-de-peso-cero.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Ejemplo de peso cero" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-07-ejemplo-de-peso-cero_thumb.png?w=644&#038;h=79" alt="Ejemplo de peso cero" width="644" height="79" border="0" /></a></p>
<p style="text-align:justify;" align="justify">El valor del peso es de tipo <strong>float</strong>, por lo que podemos utilizar decimales si queremos más precisión (y complicarnos la vida innecesariamente).</p>
<p style="text-align:justify;" align="justify">No es necesario, como se menciona en algunos textos, que la suma de los pesos sea 1. Los pesos pueden sumar cualquier cantidad salvo que se utilice la propiedad <strong>android:weightSum</strong> de <strong>LinearLayout</strong>. En ese caso, la suma no podrá superar la cifra que se especifique. Esto puede servir para determinar la proporción que ocupa una vista sin asignar peso a las demás. Por ejemplo, si la suma se establece a 1 y se asigna un peso de 0,3, la vista ocupará el 30% del espacio. No lo usarás a menudo.</p>
<h3 align="justify">Uso de LinearLayout en XML y en Java</h3>
<p style="text-align:justify;" align="justify">Tomemos como ejemplo la interfaz de usuario que se muestra en la siguiente captura, creada mediante la combinación de varios <strong>LinearLayout</strong>:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-08-ejemplo-con-varios-linearlayout.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Ejemplo con varios LinearLayout" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-08-ejemplo-con-varios-linearlayout_thumb.png?w=644&#038;h=358" alt="Ejemplo con varios LinearLayout" width="644" height="358" border="0" /></a></p>
<p style="text-align:justify;" align="justify">El código XML que permite crear ese diseño es el siguiente:</p>
<pre class="brush: xml; gutter: false; pad-line-numbers: true; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:id=&quot;@+id/principal&quot;
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;fill_parent&quot;
    android:orientation=&quot;vertical&quot; &gt;

    &lt;LinearLayout
        android:id=&quot;@+id/num_telefono&quot;
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:baselineAligned=&quot;true&quot;
        android:orientation=&quot;horizontal&quot; &gt;

        &lt;TextView
            android:id=&quot;@+id/telefono&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:paddingLeft=&quot;2sp&quot;
            android:paddingRight=&quot;2sp&quot;
            android:text=&quot;Teléfono:&quot;
            android:textSize=&quot;17sp&quot; /&gt;

        &lt;EditText
            android:id=&quot;@+id/prefijo&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_weight=&quot;3&quot;
            android:textSize=&quot;17sp&quot; /&gt;

        &lt;EditText
            android:id=&quot;@+id/numero&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_weight=&quot;9&quot;
            android:textSize=&quot;17sp&quot; /&gt;

    &lt;/LinearLayout&gt;

    &lt;LinearLayout
        android:layout_width=&quot;fill_parent&quot;
        android:layout_height=&quot;fill_parent&quot;
        android:orientation=&quot;vertical&quot; &gt;

        &lt;LinearLayout
            android:layout_width=&quot;fill_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:orientation=&quot;horizontal&quot; &gt;

            &lt;TextView
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
                android:paddingLeft=&quot;2sp&quot;
                android:paddingRight=&quot;2sp&quot;
                android:text=&quot;Descripción:&quot;
                android:textSize=&quot;17sp&quot; /&gt;

            &lt;TextView
                android:layout_width=&quot;fill_parent&quot;
                android:layout_height=&quot;wrap_content&quot;
                android:gravity=&quot;right&quot;
                android:paddingRight=&quot;2sp&quot;
                android:text=&quot;OK&quot;
                android:textColor=&quot;#00AA00&quot;
                android:textSize=&quot;17sp&quot; /&gt;

        &lt;/LinearLayout&gt;

        &lt;EditText
            android:id=&quot;@+id/descripcion&quot;
            android:layout_width=&quot;fill_parent&quot;
            android:layout_height=&quot;fill_parent&quot; /&gt;

    &lt;/LinearLayout&gt;

&lt;/LinearLayout&gt;
</pre>
<p style="text-align:justify;" align="justify">El equivalente en Java es el que se muestra a continuación:</p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:052bc3f2-f3f8-49eb-9ad3-58f468126c6e" class="wlWriterEditableSmartContent" style="margin:0;display:inline;float:none;padding:0;">
<pre class="brush: java; gutter: false; pad-line-numbers: true; title: ; notranslate">
   /** Called when the activity is first created. */
   @Override
   public void onCreate (Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);

      DisplayMetrics met = getResources().getDisplayMetrics();

      // Texto &quot;Teléfono:&quot;
      TextView telefono = new TextView(this);
      telefono.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.WRAP_CONTENT,
         LayoutParams.WRAP_CONTENT));
      telefono.setPadding(
         (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 2, met),
         0,
         (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 2, met),
         0);
      telefono.setText(&quot;Teléfono:&quot;);
      telefono.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);

      // Cuadro de texto para el prefijo
      EditText prefijo = new EditText(this);
      prefijo.setLayoutParams(new LinearLayout.LayoutParams(
         LayoutParams.WRAP_CONTENT,
         LayoutParams.WRAP_CONTENT,
         3));
      prefijo.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);

      // Cuadro de texto para el número
      EditText numero = new EditText(this);
      numero.setLayoutParams(new LinearLayout.LayoutParams(
         LayoutParams.WRAP_CONTENT,
         LayoutParams.WRAP_CONTENT,
         9));
      numero.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);

      // Diseño para el número de teléfono
      LinearLayout num_telefono = new LinearLayout(this);
      num_telefono.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.FILL_PARENT,
         LayoutParams.WRAP_CONTENT));
      num_telefono.setBaselineAligned(true);
      num_telefono.setOrientation(LinearLayout.HORIZONTAL);
      num_telefono.addView(telefono);
      num_telefono.addView(prefijo);
      num_telefono.addView(numero);

      // Texto &quot;Descripción:&quot;
      TextView desc = new TextView(this);
      desc.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.WRAP_CONTENT,
         LayoutParams.WRAP_CONTENT));
      desc.setPadding(
         (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 2, met),
         0,
         (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 2, met),
         0);
      desc.setText(&quot;Descripción:&quot;);
      desc.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);

      // Texto &quot;OK&quot;
      TextView ok = new TextView(this);
      ok.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.FILL_PARENT,
         LayoutParams.WRAP_CONTENT));
      ok.setGravity(Gravity.RIGHT);
      ok.setPadding(
         0,
         0,
         (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 2, met),
         0);
      ok.setText(&quot;OK&quot;);
      ok.setTextColor(Color.parseColor(&quot;#00AA00&quot;));
      ok.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);

      // Diseño para la línea de texto
      LinearLayout textos = new LinearLayout(this);
      textos.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.FILL_PARENT,
         LayoutParams.WRAP_CONTENT));
      textos.setOrientation(LinearLayout.HORIZONTAL);
      textos.addView(desc);
      textos.addView(ok);

      // Cuadro de texto para la descripción
      EditText descripcion = new EditText(this);
      descripcion.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.FILL_PARENT,
         LayoutParams.FILL_PARENT));

      // Diseño para la parte inferior
      LinearLayout inferior = new LinearLayout(this);
      inferior.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.FILL_PARENT,
         LayoutParams.FILL_PARENT));
      inferior.setOrientation(LinearLayout.VERTICAL);
      inferior.addView(textos);
      inferior.addView(descripcion);

      // Diseño principal de la actividad
      LinearLayout principal = new LinearLayout(this);
      principal.setLayoutParams(new ViewGroup.LayoutParams(
         LayoutParams.FILL_PARENT,
         LayoutParams.FILL_PARENT));
      principal.setOrientation(LinearLayout.VERTICAL);
      principal.addView(num_telefono);
      principal.addView(inferior);

      setContentView(principal);
   }
</pre>
</div>
<p style="text-align:justify;" align="justify">La forma de construir el diseño por código es similar a la que ya hemos visto en posts anteriores: primero se crean los widgets, luego el diseño que los contiene directamente y después se añaden los primeros dentro del segundo. Se sigue en sentido ascendente, creando los contenedores superiores e insertando en ellos las vistas que tienen que contener. Lo último que se crea es el diseño principal de la vista, al que se añade todo el contenido. El último paso consiste en asignar ese diseño principal a la vista, con el método <strong>setContentView</strong>.</p>
<p style="text-align:justify;" align="justify">Para asignar el peso a los <strong>EditText</strong> se ha usado la clase <strong>LayoutParams</strong> que se define en <strong>LinearLayout</strong> en lugar de la que incluye <strong>ViewGroup</strong> y que se ha utilizado en el resto de los casos. <strong>LinearLayout.LayoutParams</strong> proporciona un constructor que, además de los parámetros para el ancho y el alto de la vista, permite especificar un valor para el peso.</p>
<p style="text-align:justify;" align="justify">Para asignar el padding de los widgets que lo necesitan, se ha utilizado el método <strong>setPadding</strong> que incluye la clase <strong>TextView</strong>. A diferencia de la versión XML, en Java no tenemos métodos separados para cada padding y es necesario especificar los cuatro valores en todas las ocasiones. Por suerte, podemos usar el valor cero para los límites en los que no queramos colocar un padding.</p>
<p style="text-align:justify;" align="justify">En este ejemplo, la gravedad (como propiedad) no la hemos usado en un diseño, sino en un widget. En concreto, en un <strong>TextView</strong>. Como veremos más adelante, muchos widgets incorporan propiedades similares a las de los diseños. En algunos casos, ambos las heredan de la clase <strong>View</strong>. En otros casos, como en este, simplemente definen la misma propiedad y con el mismo nombre.</p>
<p style="text-align:justify;" align="justify">La propiedad <strong>android:gravity</strong> de <strong>TextView</strong> funciona exactamente igual y permite los mismos valores que su homóloga en <strong>LinearLayout</strong>, de la que hemos hablado más arriba. En Java, los posibles valores los proporciona la clase <strong>Gravity</strong>.</p>
<p style="text-align:justify;" align="justify">En este caso se ha utilizado la propiedad <strong>android:gravity</strong> en lugar del parámetro <strong>android:layout_gravity</strong> porque el <strong>TextView</strong> que se quería alinear a la derecha está incluido en un <strong>LinearLayout</strong> horizontal. Como ya hemos explicado, una gravedad horizontal utilizada en un <strong>LinearLayout</strong> también horizontal se ignora. Para conseguir el efecto deseado (que el texto <code><strong><span style="color:#008000;">OK</span></strong></code> quedara alineado a la derecha) ha sido necesario hacer que el <strong>TextView</strong> ocupara todo el espacio disponible (atributo <strong>android:width</strong> con valor <code><strong>FILL_PARENT</strong></code>) y usar gravedad derecha en el contenido.</p>
<p style="text-align:justify;" align="justify">Por último, para definir el color del texto <code><strong><span style="color:#008000;">OK</span></strong></code> en el código Java se ha utilizado el método <strong>parseColor</strong> de la clase <strong>Color</strong>. Este método acepta la misma cadena de texto que permite definir colores en un archivo XML.</p>
<p style="text-align:justify;" align="justify">Hay, no obstante, otras formas de crear y utilizar colores tanto en XML como en Java. Las veremos en un futuro post.</p>
<p class="sticky" style="text-align:center;" align="center">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2012/09/15/diseos-android-bsicos-linearlayout/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">811</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-01-opciones-de-baselinealigned_thumb.png" medium="image">
			<media:title type="html">Opciones de baselineAligned</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-02-ejemplo-de-gravity_thumb.png" medium="image">
			<media:title type="html">Ejemplo de gravity</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-03-ejemplo-de-gravity-y-layout_gravity_thumb.png" medium="image">
			<media:title type="html">Ejemplo de gravity y layout_gravity</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-04-ejemplo-de-layout_gravity-en-linearlayout-horizontal_thumb.png" medium="image">
			<media:title type="html">Ejemplo de layout_gravity en LinearLayout horizontal</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-05-ejemplo-de-layout_gravity-en-linearlayout-vertical_thumb.png" medium="image">
			<media:title type="html">Ejemplo de layout_gravity en LinearLayout vertical</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-06-ejemplo-de-pesos_thumb.png" medium="image">
			<media:title type="html">Ejemplo de pesos</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-07-ejemplo-de-peso-cero_thumb.png" medium="image">
			<media:title type="html">Ejemplo de peso cero</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0035-08-ejemplo-con-varios-linearlayout_thumb.png" medium="image">
			<media:title type="html">Ejemplo con varios LinearLayout</media:title>
		</media:content>
	</item>
		<item>
		<title>Especializaciones del dise&#241;o FrameLayout: ScrollView y HorizontalScrollView</title>
		<link>https://columna80.wordpress.com/2012/09/01/especializaciones-del-diseo-framelayout-scrollview-y-horizontalscrollview/</link>
					<comments>https://columna80.wordpress.com/2012/09/01/especializaciones-del-diseo-framelayout-scrollview-y-horizontalscrollview/#comments</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Sat, 01 Sep 2012 17:22:18 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=785</guid>

					<description><![CDATA[En el post anterior vimos las características del diseño FrameLayout y ejemplos de cómo utilizarlo en nuestras aplicaciones. Es un diseño muy sencillo y muy eficiente, motivo por el cual se usa como base para otras muchas vistas. En este post me voy a centrar en dos de las más parecidas: ScrollView y HorizontalScrollView. Ambas [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;" align="justify">En el <a href="https://columna80.wordpress.com/2012/08/22/diseos-android-bsicos-framelayout/">post anterior</a> vimos las características del diseño <strong>FrameLayout</strong> y ejemplos de cómo utilizarlo en nuestras aplicaciones. Es un diseño muy sencillo y muy eficiente, motivo por el cual se usa como base para otras muchas vistas.</p>
<p style="text-align:justify;" align="justify">En este post me voy a centrar en dos de las más parecidas: <strong>ScrollView</strong> y <strong>HorizontalScrollView</strong>. Ambas actúan como contenedores genéricos añadiendo una funcionalidad muy concreta al <strong>FrameLayout</strong>: desplazamiento.</p>
<p style="text-align:justify;" align="justify">Veamos cómo funcionan.</p>
<p><span id="more-785"></span></p>
<h3 align="justify">ScrollView</h3>
<p style="text-align:justify;" align="justify"><strong>ScrollView</strong> es una de esas vistas que está a medio camino entre el diseño y el widget. Por un lado, se puede considerar diseño, dado que puede incluir otras vistas e impone ciertas reglas para ubicarlas y dimensionarlas. Pero, por otro lado, también tiene algo de interfaz gráfica (la barra de desplazamiento) y permite interacción con el usuario, como los widgets.</p>
<p style="text-align:justify;" align="justify">La clasifiquemos como la clasifiquemos, <strong>ScrollView</strong> es una vista muy interesante: le añade desplazamiento vertical a <strong>FrameLayout</strong>. Esto nos permite mostrar un contenido de tamaño (altura) superior al que cabría en la pantalla proporcionando al usuario la posibilidad de desplazarse a lo largo de él. Teniendo en cuenta la cantidad de pantallas con tamaños diferentes que pueden tener los dispositivos Android, está claro que esta vista es una de las que más utilizaremos en nuestras aplicaciones.</p>
<p style="text-align:justify;" align="justify">Veamos cómo usar <strong>ScrollView</strong> en un diseño XML:</p>
<pre class="brush: java; gutter: false; pad-line-numbers: true; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;ScrollView
   xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
   android:layout_width=&quot;fill_parent&quot;
   android:layout_height=&quot;wrap_content&quot;
   android:scrollbars=&quot;vertical&quot;&gt;
   &lt;LinearLayout
      android:layout_width=&quot;fill_parent&quot;
      android:orientation=&quot;vertical&quot;
      android:layout_height=&quot;fill_parent&quot;
      android:paddingRight=&quot;5px&quot; &gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;1&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;2&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;3&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;4&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;5&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;6&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;7&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;8&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;9&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;10&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;11&quot; /&gt;
      &lt;EditText
         android:layout_height=&quot;wrap_content&quot;
         android:layout_width=&quot;fill_parent&quot;
         android:text=&quot;12&quot; /&gt;
   &lt;/LinearLayout&gt;
&lt;/ScrollView&gt;
</pre>
<p style="text-align:justify;" align="justify">En el ejemplo se muestra el que seguramente será el uso más frecuente de <strong>ScrollView</strong>: como contenedor de un <strong>LinearLayout</strong> vertical. Dentro del <strong>LinearLayout</strong> se incluirán el resto de vistas de la interfaz de usuario. En el ejemplo, unos cuantos <strong>EditText</strong> que ocupan más del espacio disponible de la pantalla.</p>
<p style="text-align:justify;" align="justify">Al <strong>LinearLayout</strong> se le ha añadido un padding derecho para que la barra de desplazamiento se vea mejor al no superponerse a los cuadros de texto. Hay que tener en cuenta que normalmente la barra de desplazamiento no aparece hasta que no desplazamos el dedo por la pantalla. Puedes obtener más información sobre el padding en <a href="https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/">este post</a>.</p>
<p style="text-align:justify;" align="justify">La interfaz que se genera es esta:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-01-actividad-con-scrollview-vista-superior.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Actividad con ScrollView - Vista superior" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-01-actividad-con-scrollview-vista-superior_thumb.png?w=164&#038;h=244" alt="Actividad con ScrollView - Vista superior" width="164" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-02-actividad-con-scrollview-vista-inferior.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Actividad con ScrollView - Vista inferior" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-02-actividad-con-scrollview-vista-inferior_thumb.png?w=164&#038;h=244" alt="Actividad con ScrollView - Vista inferior" width="164" height="244" border="0" /></a></p>
<p style="text-align:justify;" align="justify">Veamos ahora cómo generar esa misma interfaz mediante código:</p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:06de577b-ed46-4f8c-8133-697f815a9870" class="wlWriterEditableSmartContent" style="margin:0;display:inline;float:none;padding:0;">
<pre class="brush: java; gutter: false; pad-line-numbers: true; title: ; notranslate">
   @Override
   public void onCreate (Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);

      LinearLayout ll = new LinearLayout(this);
      ll.setOrientation(LinearLayout.VERTICAL);
      ll.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

      for (int i = 0; i &lt; 12; i++)
      {
         ll.addView(new EditText(this), new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
      }

      ScrollView sv = new ScrollView(this);
      sv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
      sv.setVerticalScrollBarEnabled(true);
      sv.addView(ll);

      setContentView(sv);
   }
</pre>
</div>
<p style="text-align:justify;" align="justify">Esta vez he utilizado una variante del método <strong>addView</strong> que hemos usado <a href="https://columna80.wordpress.com/2011/10/09/diseando-interfaces-en-android-codificacin/">otras veces</a>, que permite especificar los parámetros de diseño de la vista que se añade en la misma llamada. Eso me permite crear directamente cada <strong>EditText</strong> en la misma sentencia en la que lo añado al <strong>ScrollView</strong>. Como todos los <strong>EditText</strong> del ejemplo son iguales, los creo y añado en un bucle.</p>
<blockquote>
<p align="justify"><strong>Nota</strong></p>
<p style="text-align:justify;" align="justify"><em>En este código no se añaden los textos numéricos que se han incluido en el XML (y que se pueden observar en la captura). Para añadirlos habría que crear primero cada objeto <strong>EditText</strong> (fuera de la llamada a <strong>addView</strong>) y añadirle luego el texto con <strong>setText</strong>. El contenido del bucle <strong>for</strong> quedaría así:</em></p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:f44c103a-32bc-4f78-beb0-c612ce90b374" class="wlWriterEditableSmartContent" style="margin:0;display:inline;float:none;padding:0;">
<pre class="brush: java; gutter: false; title: ; notranslate">
         EditText et = new EditText(this);
         et.setText(Integer.toString(i + 1));
         ll.addView(et, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
</pre>
</div>
</blockquote>
<h4 align="justify">Propiedades</h4>
<p style="text-align:justify;" align="justify"><strong>ScrollView</strong> sólo añade una propiedad a las que ya proporciona <strong>FrameLayout</strong>: <strong>android:fillViewport</strong> (<strong>setFillViewport</strong>). Ya hemos visto que <strong>ScrollView</strong> permite ver el contenido de una vista que tiene una altura superior a la que la pantalla de nuestro dispositivo es capaz de mostrar, pero, ¿qué pasa si el tamaño de la vista es inferior al del espacio disponible?</p>
<p style="text-align:justify;" align="justify">En este caso, <strong>ScrollView</strong> se comporta como cualquier otra vista, en función del valor que le demos al parámetro <strong>android:layout_height</strong>. Lo habitual, en el caso de <strong>ScrollView</strong> es que usemos el valor <code><strong>wrap_content</strong></code>, lo que hace que el tamaño del diseño se ajuste a su contenido. En esta situación, si el contenido es mayor que el espacio disponible, se mostrará todo lo que quepa permitiendo el desplazamiento. Y si el contenido es menor, el tamaño del diseño se reducirá.</p>
<p style="text-align:justify;" align="justify">Puede ocurrir que eso no sea lo que queremos. Quizás queramos que alguna vista que hayamos situado en la parte inferior del <strong>ScrollView</strong> quede alineada con la parte inferior de la pantalla aunque el resto del contenido sea menor que el espacio disponible. Usando <code><strong>wrap_content</strong></code> esas vistas quedarían más arriba.</p>
<p style="text-align:justify;" align="justify">Un primer impulso puede ser usar <code><strong>fill_parent</strong></code>. Pero eso no produce totalmente el efecto deseado. De hecho, no produce ningún efecto al usarlo en combinación con <strong>ScrollView</strong>, porque su contenido no tiene el tamaño de la pantalla como límite.</p>
<p style="text-align:justify;" align="justify">Para alcanzar nuestro objetivo necesitamos una combinación de la propiedad <strong>android:fillViewport </strong>de <strong>ScrollView</strong> junto con el parámetro <strong>android:layout_weight</strong> de <strong>LinearLayout</strong>. Este último parámetro, que explicaré con más detalle en el post sobre <strong>LinearLayout</strong>, sirve para que las vistas se repartan el espacio <em>sobrante</em>, hasta ocupar el tamaño máximo que puede tener el <strong>LinearLayout</strong>. Veamos cómo funciona esta combinación:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-03-texto-corto-y-sin-fillviewport.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Texto corto y sin fillViewport" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-03-texto-corto-y-sin-fillviewport_thumb.png?w=148&#038;h=244" alt="Texto corto y sin fillViewport" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-04-texto-corto-con-fillviewport-y-fill_parent.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Texto corto con fillViewport y fill_parent" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-04-texto-corto-con-fillviewport-y-fill_parent_thumb.png?w=148&#038;h=244" alt="Texto corto con fillViewport y fill_parent" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-05-texto-corto-con-fillviewport-y-layout_weight.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Texto corto con fillViewport y layout_weight" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-05-texto-corto-con-fillviewport-y-layout_weight_thumb.png?w=148&#038;h=244" alt="Texto corto con fillViewport y layout_weight" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-06-texto-largo-parte-superior.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Texto largo - parte superior" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-06-texto-largo-parte-superior_thumb.png?w=148&#038;h=244" alt="Texto largo - parte superior" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-07-texto-largo-parte-inferior.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Texto largo - parte inferior" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-07-texto-largo-parte-inferior_thumb.png?w=148&#038;h=244" alt="Texto largo - parte inferior" width="148" height="244" border="0" /></a></p>
<p style="text-align:justify;" align="justify">En las capturas se muestra un <strong>ScrollView</strong> que contiene un <strong>LinearLayout</strong> vertical. Dentro del <strong>LinearLayout</strong> se incluyen un <strong>TextView</strong> y un <strong>Button</strong>. El objetivo es que el botón quede siempre en parte inferior de la pantalla, pero que no se muestre hasta que el usuario desplace el texto hasta el final si resulta ser más largo de lo que se puede mostrar de una sola vez.</p>
<p style="text-align:justify;" align="justify">Cuando el texto es corto lo normal es que el botón quede justo debajo del texto, como se muestra en la primera captura. Da igual que se use el valor <code><strong>fill_parent</strong></code> para el parámetro <strong>android:layout_height</strong> del <strong>TextView</strong> o del propio <strong>LinearLayout</strong>. Ni siquiera usar el parámetro <strong>android:layout_weight</strong> en el <strong>TextView</strong> logra, por sí solo, que se expanda la vista que contiene el texto y desplace el botón hasta la parte inferior de la pantalla.</p>
<p style="text-align:justify;" align="justify">Por otro lado, si usamos únicamente <strong>android:fillViewport</strong> en el <strong>ScrollView</strong> tampoco obtendremos resultado alguno (se seguirá comportando como en la primera captura), salvo que usemos también <code><strong>fill_parent</strong></code> en el parámetro <strong>android:layout_height</strong> del <strong>TextView</strong>. En ese caso ocurrirá lo que se muestra en la segunda captura, que tampoco es lo que queremos, porque el botón queda inaccesible.</p>
<p style="text-align:justify;" align="justify">La única forma de conseguir nuestro objetivo es poner a <code><strong>true</strong></code> la propiedad <strong>android:fillViewport</strong> del <strong>ScrollView</strong> y usar el parámetro <strong>android:layout_weight</strong> en el <strong>TextView</strong>. En ese caso se verá como en la tercera captura, con el botón en la parte inferior, lo que resulta mucho más estético.</p>
<p style="text-align:justify;" align="justify">Todo esto sólo tiene utilidad cuando el texto es más corto que lo que la pantalla permite mostrar. Si el texto es largo el botón sólo resultará visible cuando el usuario desplace el <strong>ScrollView</strong>, y siempre quedará en la parte inferior (como se puede observar en las dos últimas capturas).</p>
<h4 align="justify">La barra de desplazamiento</h4>
<p style="text-align:justify;" align="justify">Las barras de desplazamiento también se controlan mediante propiedades que se traducen en atributos de la vista en el XML. Curiosamente, las propiedades relacionadas con barras de desplazamiento están definidas directamente en la clase <strong>View</strong>, por lo que, en principio, todas las vistas disponen de ellas.</p>
<p style="text-align:justify;" align="justify">Esto no significa, obviamente, que todas las vistas tengan funcionalidad de desplazamiento, ni mucho menos. Podemos forzar el uso de la barra de desplazamiento en, por ejemplo, un <strong>Button</strong>. Incluso podemos conseguir que se muestre dicha barra, haciendo que el contenido sea muy grande. Pero en ningún caso podremos desplazar ese contenido. Y tampoco es que tenga mucho sentido tratar de hacerlo, dicho sea de paso.</p>
<p style="text-align:justify;" align="justify">Además, aunque la vista pueda tener barras de desplazamiento, puede que no soporte todos los posibles valores de algunas de las propiedades. Por ejemplo, como <strong>ScrollView</strong> sólo implementa desplazamiento vertical, tratar de mostrar la barra de desplazamiento horizontal no tiene ningún efecto.</p>
<p style="text-align:justify;" align="justify">Veamos las propiedades que permiten gestionar las barras de desplazamiento:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><strong>android:scrollbars</strong> (<strong>setHorizontalScrollBarEnabled</strong>, <strong>setVerticalScrollBarEnabled</strong>): el atributo puede recibir tres valores: <code><strong>none</strong></code>, <code><strong>horizontal</strong></code> o <code><strong>vertical</strong></code>, que significa que no se muestra ninguna barra, sólo la horizontal o sólo la vertical (respectivamente). Los dos últimos se pueden usar simultáneamente separándolos con <code><strong>|</strong></code>, para mostrar ambas barras. En Java hay un método para indicar si cada barra se muestra o no.</p>
<p style="text-align:justify;">En <strong>ScrollView</strong>, el valor predeterminado es <code><strong>vertical</strong></code>. O sea, que la barra siempre se muestra. Si no queremos que aparezca hay que usar <code><strong>none</strong></code>. El valor <code><strong>horizontal</strong></code>, como ya hemos comentado, no tiene ningún efecto en <strong>ScrollView</strong>.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:scrollbarStyle </strong>(<strong>setScrollBarStyle</strong>): permite definir el estilo de la barra, lo que afecta también a su posición. Puede tener cuatro valores (entre paréntesis se indica la constante para el método Java equivalente):</p>
<ul>
<li>
<p style="text-align:justify;"><code><strong>insideOverlay</strong></code> (<strong>SCROLLBARS_INSIDE_OVERLAY</strong>): dentro del contenido (en el interior del padding) y superpuesta</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>insideInset</strong></code> (<strong>SCROLLBARS_INSIDE_INSET</strong>): dentro del contenido, pero sin superponerse</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>outsideOverlay</strong></code> (<strong>SCROLLBARS_OUTSIDE_OVERLAY</strong>): en el borde de la vista (fuera del padding) y superpuesta</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>outsideInset</strong></code> (<strong>SCROLLBARS_OUTSIDE_INSET</strong>): en el borde de la vista, pero sin superponerse.</p>
</li>
</ul>
<p style="text-align:justify;">Las siguientes capturas muestran el efecto de cada una de las opciones cuando tenemos un padding en el <strong>ScrollView</strong>:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-08-scrollview-con-estilo-insideoverlay-y-con-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo insideOverlay y con padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-08-scrollview-con-estilo-insideoverlay-y-con-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo insideOverlay y con padding" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-09-scrollview-con-estilo-insideinset-y-con-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo insideInset y con padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-09-scrollview-con-estilo-insideinset-y-con-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo insideInset y con padding" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-10-scrollview-con-estilo-outsideoverlay-y-con-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo outsideOverlay y con padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-10-scrollview-con-estilo-outsideoverlay-y-con-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo outsideOverlay y con padding" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-11-scrollview-con-estilo-outsideinset-y-con-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo outsideInset y con padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-11-scrollview-con-estilo-outsideinset-y-con-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo outsideInset y con padding" width="148" height="244" border="0" /></a></p>
<p style="text-align:justify;">Como se puede observar, los valores <em>inside</em> sitúan la barra de desplazamiento en el contenido, dejando todo el padding a la derecha. Los valores <em>outside</em>, sin embargo, sitúan la barra en el exterior del <strong>ScrollView</strong>, dejando el padding a la izquierda.</p>
<p style="text-align:justify;">La diferencia entre los valores <em>overlay</em> y los <em>inset</em> también es bastante obvia: cuando se usa <em>overlay</em> la barra se muestra sobre el área en el que se coloca (sobre el contenido del <strong>ScrollView</strong> en el caso de <code><strong>insideOverlay</strong></code> y sobre el propio padding en el caso de <code><strong>outsideOverlay</strong></code>). Usar <em>inset</em> provoca la creación un espacio propio para la barra de desplazamiento, moviendo y cambiando el tamaño del contenido del <strong>ScrollView</strong>.</p>
<p style="text-align:justify;">En las capturas se puede observar cómo los valores <em>inset</em> provocan que el padding derecho parezca mayor de lo que es, al sumársele el espacio destinado a la barra. Esto es algo que habrá que tener en cuenta si la barra sólo se muestra durante el desplazamiento, porque el contenido parecerá “descentrado” cuando la barra esté oculta.</p>
<p style="text-align:justify;">Si no tenemos padding, no hay ninguna diferencia entre situar la barra <em>inside</em> u <em>outside</em>, como se puede apreciar en las siguientes capturas:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-12-scrollview-con-estilo-insideoverlay-y-sin-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo insideOverlay y sin padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-12-scrollview-con-estilo-insideoverlay-y-sin-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo insideOverlay y sin padding" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-13-scrollview-con-estilo-insideinset-y-sin-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo insideInset y sin padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-13-scrollview-con-estilo-insideinset-y-sin-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo insideInset y sin padding" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-14-scrollview-con-estilo-outsideoverlay-y-sin-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo outsideOverlay y sin padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-14-scrollview-con-estilo-outsideoverlay-y-sin-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo outsideOverlay y sin padding" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-15-scrollview-con-estilo-outsideinset-y-sin-padding.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView con estilo outsideInset y sin padding" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-15-scrollview-con-estilo-outsideinset-y-sin-padding_thumb.png?w=148&#038;h=244" alt="ScrollView con estilo outsideInset y sin padding" width="148" height="244" border="0" /></a></p>
</li>
</ul>
</div>
<ul>
<li>
<p style="text-align:justify;"><strong>android:scrollbarFadeDuration</strong>: de forma predeterminada, la barra de desplazamiento sólo se muestra cuando se está arrastrando el contenido de la vista, desapareciendo poco tiempo después. Este atributo permite definir cuánto tiempo (en milisegundos) permanece visible la barra tras el desplazamiento.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:fadeScrollbars</strong> (<strong>setScrollbarFadingEnabled</strong>): permite activar o desactivar el desvanecimiento de la barra de desplazamiento. Si se usa con el valor <code><strong>false</strong></code>, las barras se muestran todo el tiempo. Teóricamente se debería poder conseguir el mismo efecto usando el valor cero en <strong>android:scrollbarFadeDuration</strong>, pero no siempre funciona.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:scrollbarSize</strong>: permite establecer el ancho de la barra de desplazamiento. Es de tipo <a href=" ?=">dimensión</a>, pero no funciona correctamente en algunas versiones de Android: <a href="http://code.google.com/p/android/issues/detail?id=14317">http://code.google.com/p/android/issues/detail?id=14317</a>.</p>
</li>
</ul>
<h3>HorizontalScrollView</h3>
<p style="text-align:justify;" align="justify">Este widget es idéntico a <strong>ScrollView</strong>, salvo porque el desplazamiento lo realiza horizontalmente en lugar de verticalmente. El resto del comportamiento es idéntico y las propiedades que permiten personalizar <strong>ScrollView</strong> funcionan de forma idéntica en <strong>HorizontalScrollView</strong>, por lo que no hay mucho más que añadir aquí.</p>
<h3 align="justify">Doble desplazamiento</h3>
<p style="text-align:justify;" align="justify">Android no dispone de una vista que realice ambos desplazamientos simultáneamente.</p>
<p style="text-align:justify;" align="justify">Una solución rápida puede ser incluir un <strong>HorizontalScrollView</strong> dentro de un <strong>ScrollView</strong> (o viceversa). Sin embargo, eso no provoca totalmente el efecto deseado. El problema es que la barra de desplazamiento forma parte de la vista. Si el <strong>HorizontalScrollView</strong> está dentro de un <strong>ScrollView</strong> y su tamaño vertical es superior a lo que se puede visualizar, la barra de desplazamiento del <strong>HorizontalScrollView</strong> sólo será visible cuando se esté mostrando la parte inferior de la vista:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-16-scrollview-y-horizontalscrollview-parte-superior.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView y HorizontalScrollView - Parte superior" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-16-scrollview-y-horizontalscrollview-parte-superior_thumb.png?w=148&#038;h=244" alt="ScrollView y HorizontalScrollView - Parte superior" width="148" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-17-scrollview-y-horizontalscrollview-parte-inferior.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px 0;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ScrollView y HorizontalScrollView - Parte inferior" src="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-17-scrollview-y-horizontalscrollview-parte-inferior_thumb.png?w=148&#038;h=244" alt="ScrollView y HorizontalScrollView - Parte inferior" width="148" height="244" border="0" /></a></p>
<p style="text-align:justify;" align="justify">En cualquier caso, a pesar de que la parte mostrada no incluya la barra de desplazamiento, podremos seguir moviendo el contenido a izquierda y derecha, aunque sin ver dicha barra.</p>
<p style="text-align:justify;" align="justify">Podemos hacer que el problema pase desapercibido si ocultamos ambas barras de desplazamiento, utilizando la propiedad <strong>android:scrollbars</strong> en ambas vistas.</p>
<p style="text-align:justify;" align="justify">La única forma de conseguir una vista contenedora que soporte desplazamiento en ambas direcciones mostrando correctamente las barras es crearnos una nosotros mismos. Eso queda fuera del alcance de este post, pero podéis encontrar una implementación detallada aquí: <a href="http://blog.gorges.us/2010/06/android-two-dimensional-scrollview/">http://blog.gorges.us/2010/06/android-two-dimensional-scrollview/</a></p>
<p class="sticky" style="text-align:center;" align="center">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2012/09/01/especializaciones-del-diseo-framelayout-scrollview-y-horizontalscrollview/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">785</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-01-actividad-con-scrollview-vista-superior_thumb.png" medium="image">
			<media:title type="html">Actividad con ScrollView - Vista superior</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-02-actividad-con-scrollview-vista-inferior_thumb.png" medium="image">
			<media:title type="html">Actividad con ScrollView - Vista inferior</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-03-texto-corto-y-sin-fillviewport_thumb.png" medium="image">
			<media:title type="html">Texto corto y sin fillViewport</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-04-texto-corto-con-fillviewport-y-fill_parent_thumb.png" medium="image">
			<media:title type="html">Texto corto con fillViewport y fill_parent</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-05-texto-corto-con-fillviewport-y-layout_weight_thumb.png" medium="image">
			<media:title type="html">Texto corto con fillViewport y layout_weight</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-06-texto-largo-parte-superior_thumb.png" medium="image">
			<media:title type="html">Texto largo - parte superior</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-07-texto-largo-parte-inferior_thumb.png" medium="image">
			<media:title type="html">Texto largo - parte inferior</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-08-scrollview-con-estilo-insideoverlay-y-con-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo insideOverlay y con padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-09-scrollview-con-estilo-insideinset-y-con-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo insideInset y con padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-10-scrollview-con-estilo-outsideoverlay-y-con-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo outsideOverlay y con padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-11-scrollview-con-estilo-outsideinset-y-con-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo outsideInset y con padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-12-scrollview-con-estilo-insideoverlay-y-sin-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo insideOverlay y sin padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-13-scrollview-con-estilo-insideinset-y-sin-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo insideInset y sin padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-14-scrollview-con-estilo-outsideoverlay-y-sin-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo outsideOverlay y sin padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-15-scrollview-con-estilo-outsideinset-y-sin-padding_thumb.png" medium="image">
			<media:title type="html">ScrollView con estilo outsideInset y sin padding</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-16-scrollview-y-horizontalscrollview-parte-superior_thumb.png" medium="image">
			<media:title type="html">ScrollView y HorizontalScrollView - Parte superior</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/09/0034-17-scrollview-y-horizontalscrollview-parte-inferior_thumb.png" medium="image">
			<media:title type="html">ScrollView y HorizontalScrollView - Parte inferior</media:title>
		</media:content>
	</item>
		<item>
		<title>Dise&#241;os Android b&#225;sicos: FrameLayout</title>
		<link>https://columna80.wordpress.com/2012/08/22/diseos-android-bsicos-framelayout/</link>
					<comments>https://columna80.wordpress.com/2012/08/22/diseos-android-bsicos-framelayout/#respond</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Wed, 22 Aug 2012 17:53:56 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=744</guid>

					<description><![CDATA[Llevo ya unos cuantos posts dedicados a la interfaz de usuario en Android. Empecé hablando de las actividades y su ciclo de vida, y continué con varios posts sobre las vistas, la forma en que se organizan en diseños y cómo se muestran esos diseños en las actividades. También hemos visto ya los dos tipos [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;">Llevo ya unos cuantos posts dedicados a la interfaz de usuario en Android. Empecé hablando de las <a href="https://columna80.wordpress.com/2011/07/29/introduccin-a-las-actividades-de-android/">actividades</a> y su <a href="https://columna80.wordpress.com/2011/09/03/ciclo-de-vida-de-las-actividades-de-android-i/">ciclo de vida</a>, y continué con varios posts sobre las vistas, la forma en que se organizan en diseños y cómo se muestran esos diseños en las actividades. También hemos visto ya los dos tipos principales de vistas que tenemos, <a href="https://columna80.wordpress.com/2011/09/12/las-vistas-android-diseos-y-widgets/">diseños y widgets</a> e incluso he enumerado algunos de los más usuales, incluyendo una breve descripción de su cometido.</p>
<p style="text-align:justify;">Es el momento ahora de profundizar más en esas vistas, viendo más detalles sobre ellas y ejemplos de uso. Empezaremos por los diseños básicos, dado que será lo primero que tengamos que crear en nuestra actividad, para subdividir el espacio y controlar la ubicación de los widgets. En concreto, comenzaremos por el <strong>FrameLayout</strong>, el diseño más sencillo de todos los disponibles, pero también el más eficiente.</p>
<p style="text-align:justify;"><strong>FrameLayout</strong> no realiza ninguna distribución de las vistas, simplemente las coloca unas encima de otras. Esto le evita tener que relacionar los tamaños de unas vistas con los de las demás, por lo que se ahorra recorridos del árbol de vistas, tardando menos en mostrar su contenido.</p>
<p><span id="more-744"></span></p>
<h3>La gravedad</h3>
<p style="text-align:justify;">Que <strong>FrameLayout</strong> coloque las vistas una sobre otra no significa que todas se alineen automáticamente a la esquina superior izquierda del diseño. Por un lado tenemos el padding. El diseño, al ser una vista, también tiene esa propiedad. Y por otro lado tenemos el margen, si el <strong>FrameLayout</strong> está contenido en otro diseño que lo soporta. Puedes ver más detalles sobre padding y margen en <a href="https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/">este post</a>.</p>
<p style="text-align:justify;">Pero, además de todo esto, tenemos un parámetro que nos permite controlar el alineamiento de las vistas contenidas en el diseño: la gravedad. Este parámetro, definido en <strong>FrameLayout.LayoutParams</strong>, y que se corresponde con el atributo <strong>android:layout_gravity</strong> no es exclusivo de <strong>FrameLayout</strong>. <a title="Diseños Android básicos: LinearLayout" href="https://columna80.wordpress.com/2012/09/15/diseos-android-bsicos-linearlayout/"><strong>LinearLayout</strong></a> también lo proporciona y, por herencia, también <a title="Diseños Android básicos: TableLayout" href="https://columna80.wordpress.com/2012/11/05/diseos-android-bsicos-tablelayout/"><strong>TableLayout</strong></a>, <strong>TableRow</strong> e incluso <strong>RadioGroup</strong>. Los valores disponibles para el parámetro y el resultado obtenido con cada uno de ellos son comunes para todos estos diseños, por lo que les será de aplicación lo que voy a explicar a continuación.</p>
<p style="text-align:justify;">La gravedad permite indicar cómo se debe alinear la vista sobre la que se aplica, tanto horizontal como verticalmente, en relación a los límites del área disponible para el contenido del <strong>FrameLayout</strong>. Este área incluye todo el espacio que el <strong>FrameLayout</strong> ocupa en la actividad menos el padding que se haya establecido.</p>
<p style="text-align:justify;">En la siguiente lista se enumeran algunos de los valores que se pueden utilizar para establecer la gravedad. En el archivo XML, al atributo <strong>android:layout_gravity</strong> se le asigna una cadena de texto que contiene uno o más de estos valores. Si hay más de uno se separan mediante <code><strong>|</strong></code>. Para cada uno de estos valores existe una constante de igual nombre que se puede utilizar para asignar la gravedad mediante código Java. De forma similar, si en Java usa más de una constante, se agregan mediante el operador lógico <strong>|</strong>:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><code><strong>top</strong></code> y <code><strong>bottom</strong></code>: alinean el borde superior/inferior de la vista con el del área útil del diseño, sin alterar el tamaño de la vista.</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>left</strong></code> y <code><strong>right</strong></code>: alinean el borde izquierdo/derecho de la vista con el del área útil del diseño, sin alterar el tamaño de la vista.</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>center_horizontal</strong></code> y <code><strong>center_vertical</strong></code>: centran la vista horizontal o verticalmente en el área útil del diseño sin alterar su tamaño.</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>center</strong></code>: centra la vista vertical y horizontalmente, de forma simultánea, en el área útil del diseño sin alterar su tamaño.</p>
</li>
</ul>
</div>
<p style="text-align:justify;">En el siguiente ejemplo podemos ver el funcionamiento de las primeras constantes enumeradas:</p>
<pre class="brush: xml; gutter: false; pad-line-numbers: true; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;FrameLayout
   xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
   android:layout_width=&quot;fill_parent&quot;
   android:layout_height=&quot;fill_parent&quot;&gt;
   &lt;TextView
      android:layout_width=&quot;wrap_content&quot;
      android:layout_height=&quot;wrap_content&quot;
      android:text=&quot;Sin gravedad&quot;
      android:textSize=&quot;23sp&quot;
      android:background=&quot;#080&quot; /&gt;
   &lt;TextView
      android:layout_width=&quot;wrap_content&quot;
      android:layout_height=&quot;wrap_content&quot;
      android:text=&quot;right&quot;
      android:background=&quot;#080&quot;
      android:textSize=&quot;23sp&quot;
      android:layout_gravity=&quot;right&quot; /&gt;
   &lt;TextView
      android:layout_width=&quot;wrap_content&quot;
      android:layout_height=&quot;wrap_content&quot;
      android:text=&quot;bottom&quot;
      android:background=&quot;#080&quot;
      android:textSize=&quot;23sp&quot;
      android:layout_gravity=&quot;bottom&quot; /&gt;
   &lt;TextView
      android:layout_width=&quot;wrap_content&quot;
      android:layout_height=&quot;wrap_content&quot;
      android:text=&quot;bottom|right&quot;
      android:background=&quot;#080&quot;
      android:textSize=&quot;23sp&quot;
      android:layout_gravity=&quot;bottom|right&quot; /&gt;
   &lt;TextView
      android:layout_width=&quot;wrap_content&quot;
      android:layout_height=&quot;wrap_content&quot;
      android:text=&quot;center_vertical&quot;
      android:background=&quot;#080&quot;
      android:textSize=&quot;23sp&quot;
      android:layout_gravity=&quot;center_vertical&quot; /&gt;
   &lt;TextView
      android:layout_width=&quot;wrap_content&quot;
      android:layout_height=&quot;wrap_content&quot;
      android:text=&quot;center_horizontal&quot;
      android:background=&quot;#080&quot;
      android:textSize=&quot;23sp&quot;
      android:layout_gravity=&quot;center_horizontal&quot; /&gt;
&lt;/FrameLayout&gt;
</pre>
<p>Este ejemplo genera la siguiente interfaz de usuario:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2012/08/0033-01-usos-bsicos-de-la-gravedad.png" target="_blank"><img loading="lazy" style="background-image:none;margin:5px auto;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;" title="Usos básicos de la gravedad" alt="Usos básicos de la gravedad" src="https://columna80.wordpress.com/wp-content/uploads/2012/08/0033-01-usos-bsicos-de-la-gravedad_thumb.png?w=244&#038;h=164" height="164" width="244" /></a></p>
<p style="text-align:justify;">La gravedad puede tomar más valores que los descritos aquí, pero su funcionamiento es algo más complejo, por lo que los trataré con detalle en un futuro post.</p>
<h3>Crear FrameLayout por código</h3>
<p style="text-align:justify;">Ya hemos visto en el ejemplo de uso del parámetro gravedad cómo se utiliza el diseño <strong>FrameLayout</strong> en XML. Veamos ahora cómo crear esa misma interfaz de usuario por código:</p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:6f5d10be-d239-43d6-9059-cbf316872e0b" class="wlWriterEditableSmartContent" style="margin:0;display:inline;float:none;padding:0;">
<pre class="brush: java; gutter: false; pad-line-numbers: true; title: ; notranslate">
   @Override
   public void onCreate (Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);

      TextView tv1 = new TextView(this);
      tv1.setLayoutParams(new ViewGroup.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT));
      tv1.setText(&quot;Sin gravedad&quot;);
      tv1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv1.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv2 = new TextView(this);
      tv2.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.RIGHT));
      tv2.setText(&quot;right&quot;);
      tv2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv2.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv3 = new TextView(this);
      tv3.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.BOTTOM));
      tv3.setText(&quot;bottom&quot;);
      tv3.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv3.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv4 = new TextView(this);
      tv4.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.BOTTOM | Gravity.RIGHT));
      tv4.setText(&quot;bottom|right&quot;);
      tv4.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv4.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv5 = new TextView(this);
      tv5.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.CENTER_VERTICAL));
      tv5.setText(&quot;center_vertical&quot;);
      tv5.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv5.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv6 = new TextView(this);
      tv6.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.CENTER_HORIZONTAL));
      tv6.setText(&quot;center_horizontal&quot;);
      tv6.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv6.setBackgroundColor(Color.rgb(0, 136, 0));

      FrameLayout fl = new FrameLayout(this);
      fl.addView(tv1);
      fl.addView(tv2);
      fl.addView(tv3);
      fl.addView(tv4);
      fl.addView(tv5);
      fl.addView(tv6);

      setContentView(fl);
   }
</pre>
</div>
<p style="text-align:justify;">En el código se observa cómo se crean primero los <strong>TextView</strong> y luego el <strong>FrameLayout</strong>. Los <strong>TextView</strong> se añaden al <strong>FrameLayout</strong> y después se asigna el diseño a la actividad para que se muestre. Se puede observar también cómo la gravedad se asigna a cada widget como parámetro, creando un <strong>FrameLayout.</strong><strong>LayoutParams</strong> y pasándosela al constructor. Además, no es necesario asignar las constantes <code><strong>fill_parent</strong></code> a los atributos correspondientes del <strong>FrameLayout</strong> porque ese es el valor que tienen de forma predeterminada.</p>
<p style="text-align:justify;">Conviene aclarar que los valores 0, 136 y 0 que se le pasan al método <strong>rgb</strong> de la clase <strong>Color</strong>, son los equivalentes decimales a la cadena hexadecimal que hemos utilizado en el archivo XML: <code>#080</code>. La conversión no es directa porque en XML hemos usado el formato #RGB, que sólo emplea un dígito hexadecimal para cada color. En este caso, los valores posibles para cada color oscilan entre 0 y 15. Sin embargo, los valores que admite el método <strong>rgb</strong> oscilan entre 0 y 255, por lo que la conversión se ha tenido que hacer de forma proporcional.</p>
<p style="text-align:justify;">Finalmente, comentar que la clase <strong>TextView</strong> dispone de un método <strong>setTextSize</strong> que permite especificar una dimensión junto con sus unidades para establecer el tamaño del texto. De esta forma nos ahorramos tener que calcular primero los píxeles equivalentes utilizando los métodos que vimos en el <a href="https://columna80.wordpress.com/2011/10/03/recursos-en-android-dimensiones/">post dedicado a las dimensiones</a>.</p>
<p style="text-align:justify;">En el <a title="Especializaciones del diseño FrameLayout: ScrollView y HorizontalScrollView" href="https://columna80.wordpress.com/2012/09/01/especializaciones-del-diseo-framelayout-scrollview-y-horizontalscrollview/">próximo post</a> veremos algunas especializaciones del <strong>FrameLayout</strong>: clases que heredan de este diseño, incorporando su funcionalidad básica y añadiendo funcionalidad particular.</p>
<p class="sticky" style="text-align:center;">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2012/08/22/diseos-android-bsicos-framelayout/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">744</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2012/08/0033-01-usos-bsicos-de-la-gravedad_thumb.png" medium="image">
			<media:title type="html">Usos básicos de la gravedad</media:title>
		</media:content>
	</item>
		<item>
		<title>Dise&#241;ando interfaces en Android: codificaci&#243;n</title>
		<link>https://columna80.wordpress.com/2011/10/09/diseando-interfaces-en-android-codificacin/</link>
					<comments>https://columna80.wordpress.com/2011/10/09/diseando-interfaces-en-android-codificacin/#comments</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Sun, 09 Oct 2011 16:27:27 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Actividades]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Manifiesto]]></category>
		<category><![CDATA[SDK]]></category>
		<category><![CDATA[Vistas]]></category>
		<category><![CDATA[XML]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=730</guid>

					<description><![CDATA[Hagamos un rápido repaso de lo principal que hemos visto hasta ahora sobre creación de interfaces de usuario en Android: Las aplicaciones Android muestran su interfaz por medio de las actividades (post), las cuales tienen un ciclo de vida que es mucho más que simplemente mostrarse ante el usuario y permitirle que interactúe (post 1 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;" align="justify">Hagamos un rápido repaso de lo principal que hemos visto hasta ahora sobre creación de interfaces de usuario en Android:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;">Las aplicaciones Android muestran su interfaz por medio de las actividades (<a href="https://columna80.wordpress.com/2011/07/29/introduccin-a-las-actividades-de-android/">post</a>), las cuales tienen un ciclo de vida que es mucho más que simplemente mostrarse ante el usuario y permitirle que interactúe (<a href="https://columna80.wordpress.com/2011/09/03/ciclo-de-vida-de-las-actividades-de-android-i/">post 1</a> y <a href="https://columna80.wordpress.com/2011/09/07/ciclo-de-vida-de-las-actividades-de-android-ii/">post 2</a>).</p>
</li>
<li>
<p style="text-align:justify;">La interfaz de usuario se crea incluyendo vistas en las actividades. El hecho de que algunas de esas vistas actúen como contenedores de otras vistas permite diseñar interfaces de usuario complejas partiendo de elementos bastante sencillos (<a href="https://columna80.wordpress.com/?p=611">post</a>).</p>
</li>
<li>
<p style="text-align:justify;">La mejor forma de diseñar una interfaz de usuario es hacerlo en un archivo XML, accediendo a las propiedades de las vistas por medio de atributos directamente en el código XML (<a href="https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/">post</a>). Por su parte, las vistas contenedoras proporcionan parámetros de diseño a las vistas que contienen, accesibles también por medio de atributos en el XML (<a href="https://columna80.wordpress.com/2011/09/20/diseando-interfaces-en-android-parmetros/">post</a>).</p>
</li>
</ul>
</div>
<p style="text-align:justify;" align="justify">Aunque en todo momento hemos ido relacionando los elementos que se utilizan en XML con clases y métodos Java, lo cierto es que a la hora de proponer ejemplos me he limitado a mostrar código XML. No hemos visto cómo utilizar esos archivos XML en un proyecto ni cómo crear esas mismas interfaces directamente en Java. En este post voy a poner remedio a ambas cosas.</p>
<p><span id="more-730"></span></p>
<h3 align="justify">Utilizar el diseño en una actividad</h3>
<p style="text-align:justify;" align="justify">En el <a href="https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/">post sobre diseño en XML</a> utilizamos como ejemplo el código que se muestra en la siguiente captura:</p>
<p align="justify"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Ejemplo de diseño en XML" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-01-ejemplo-de-diseo-en-xml.png?w=518&#038;h=417" alt="Ejemplo de diseño en XML" width="518" height="417" border="0" /></p>
<p style="text-align:justify;" align="justify">Si queremos utilizar este diseño necesitamos un proyecto y una actividad. Ya vimos en un <a href="https://columna80.wordpress.com/2011/03/15/la-primera-aplicacin-android/">post anterior</a> cómo crear un proyecto. Veamos ahora cómo agregar una nueva actividad:</p>
<div align="justify">
<ol>
<li>
<p style="text-align:justify;">Desplegamos el proyecto en la vista <strong>Project Explorer</strong> (o <strong>Package Explorer</strong>, la que más nos guste) de Eclipse y hacemos doble clic en el archivo <code>AndroidManifest.xml</code> para abrirlo.</p>
</li>
<li>
<p style="text-align:justify;">En la parte inferior del editor del manifiesto seleccionamos la pestaña <strong>Application</strong>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-02-editor-del-manifiesto-de-la-aplicacin-android.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Editor del manifiesto de la aplicación Android" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-02-editor-del-manifiesto-de-la-aplicacin-android_thumb.png?w=244&#038;h=224" alt="Editor del manifiesto de la aplicación Android" width="244" height="224" border="0" /></a></li>
<li>
<p style="text-align:justify;">En la parte inferior de la pestaña, en la sección <strong>Application Nodes</strong>, pulsamos el botón <strong>Add</strong>. Se muestra una lista de los distintos tipos de nodos que podemos crear.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-03-seleccin-del-tipo-de-nodo-de-aplicacin-a-crear.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Selección del tipo de nodo de aplicación a crear" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-03-seleccin-del-tipo-de-nodo-de-aplicacin-a-crear_thumb.png?w=223&#038;h=244" alt="Selección del tipo de nodo de aplicación a crear" width="223" height="244" border="0" /></a></li>
<li>
<p style="text-align:justify;">Seleccionamos <strong>Activity</strong> y pulsamos <strong>OK</strong> (no es necesario escribir nada en el cuadro de texto). Se añade un nuevo nodo <strong>Activity</strong> a la lista y se muestra una lista de atributos a la derecha (<strong>Attributes for Activity</strong>). Podemos pulsar sobre los triángulos que hay a la izquierda de <strong>Application Toggle</strong> y <strong>Application Attributes</strong> para contraer esas secciones y así disponer de más espacio par los atributos de la actividad:</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-04-manifiesto-atributos-de-la-actividad.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Manifiesto - Atributos de la actividad" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-04-manifiesto-atributos-de-la-actividad_thumb.png?w=244&#038;h=224" alt="Manifiesto - Atributos de la actividad" width="244" height="224" border="0" /></a></li>
<li>
<p style="text-align:justify;">De todos los atributos disponibles, el único que es obligatorio (y el único que vamos a definir) es el nombre de la actividad. En lugar de escribir el nombre directamente en el cuadro de texto, pulsamos en <strong>Name*</strong> para abrir el cuadro de diálogo <strong>New Java Class</strong>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-05-nueva-clase-java.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Nueva clase Java" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-05-nueva-clase-java_thumb.png?w=208&#038;h=244" alt="Nueva clase Java" width="208" height="244" border="0" /></a></li>
<li>
<p style="text-align:justify;">Lo único que tenemos que hacer es escribir el nombre de la actividad en el cuadro de texto <strong>Name</strong> y pulsar <strong>Finish</strong>. El nombre tiene que cumplir los requisitos para los nombres de clases en Java (sin símbolos, sin espacios, etc.). El resto de campos los dejamos como están. Tras pulsar <strong>Finish</strong> se cierra el cuadro de diálogo y se muestra el código de la recién creada actividad.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-06-cdigo-predeterminado-de-una-actividad.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Código predeterminado de una actividad" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-06-cdigo-predeterminado-de-una-actividad_thumb.png?w=244&#038;h=215" alt="Código predeterminado de una actividad" width="244" height="215" border="0" /></a></li>
<li>
<p style="text-align:justify;">No conviene que nos olvidemos de guardar los cambios que hemos hecho en el manifiesto. Para ello pulsamos en su pestaña y seleccionamos <strong>File</strong> | <strong>Save</strong> en el menú de Eclipse.</p>
</li>
</ol>
</div>
<p style="text-align:justify;" align="justify">Crear una nueva actividad en el proyecto no nos añade un diseño XML (porque no es algo obligatorio), por lo que tendremos que agregarlo nosotros siguiendo los siguientes pasos:</p>
<div align="justify">
<ol>
<li>
<p style="text-align:justify;">Desplegamos el proyecto en la vista <strong>Package Explorer</strong> de Eclipse, desplegamos la carpeta <code>res</code> y pulsamos con el botón derecho del ratón sobre <code>layout</code>. En el menú que se despliega seleccionamos <strong>New</strong> | <strong>Other</strong>. Se nos muestra una lista, organizada por carpetas, de todo lo que podemos crear en nuestra versión de Eclipse.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-07-elementos-disponibles-en-eclipse.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Elementos disponibles en Eclipse" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-07-elementos-disponibles-en-eclipse_thumb.png?w=244&#038;h=233" alt="Elementos disponibles en Eclipse" width="244" height="233" border="0" /></a></li>
<li>
<p style="text-align:justify;">Desplegamos la carpeta <strong>Android</strong> y seleccionamos <strong>Android XML File</strong>. Después pulsamos <strong>Next</strong> para mostrar el cuadro de diálogo <strong>New Android XML File</strong>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-08-nuevo-archivo-xml-para-android.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Nuevo archivo XML para Android" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-08-nuevo-archivo-xml-para-android_thumb.png?w=227&#038;h=244" alt="Nuevo archivo XML para Android" width="227" height="244" border="0" /></a></li>
<li>
<p style="text-align:justify;">Este cuadro de diálogo sirve para crear muchos de los diferentes archivos XML de recursos que se pueden utilizar en un proyecto Android. Como nosotros vamos a crear un diseño, nos aseguraremos de que esté seleccionada la opción <strong>Layout</strong> en la lista <strong>What type of resource would you like to create?</strong>. Luego, escribimos el nombre que le queremos dar al archivo en el cuadro de texto <strong>File</strong> y pulsamos <strong>Finish</strong>. Android exige que escribamos el nombre en minúsculas. La extensión no es necesario escribirla. Al terminar se abre el nuevo archivo creado en el modo de edición gráfica.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-09-editor-grfico-de-diseos.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Editor gráfico de diseños" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-09-editor-grfico-de-diseos_thumb.png?w=244&#038;h=215" alt="Editor gráfico de diseños" width="244" height="215" border="0" /></a></li>
</ol>
</div>
<p style="text-align:justify;" align="justify">Como lo que queremos es escribir directamente el código (o copiarlo del <a href="https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/">otro post</a>), tenemos que pulsar sobre la pestaña inferior con el nombre del archivo, a la derecha de <strong>Graphical Layout,</strong> para mostrar el editor de código XML. Ahora sólo nos queda reemplazar el código que se genera de forma predeterminada por el nuestro y guardar el archivo.</p>
<p style="text-align:justify;" align="justify">El lugar adecuado para cargar el diseño es, como <a href="https://columna80.wordpress.com/2011/09/03/ciclo-de-vida-de-las-actividades-de-android-i/">ya vimos</a>, el método <strong>onCreate</strong>. El código necesario para que el diseño que hemos creado en XML se muestre en la actividad es el siguiente, asumiendo que hemos guardado el XML anterior en la carpeta <code>res/layout</code> con el nombre <code>prueba.xml</code>:</p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:25c0eca1-621f-462f-b2cb-6ac86cc07453" class="class" style="display:inline;float:none;margin:0;padding:0;">
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:67743f48-9316-4124-b4bf-494678d339a7" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<pre class="brush: java; auto-links: false; gutter: false; title: ; notranslate">
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
   super.onCreate(savedInstanceState);
   setContentView(R.layout.prueba);
}
</pre>
</div>
<div>
<p style="text-align:justify;">Como se ve en el código, lo único que hace falta para cargar un diseño completo es llamar al método <strong>setContentView</strong>. El parámetro que recibe este método es un identificador que crea el compilador al procesar el archivo XML.</p>
</div>
</div>
<p style="text-align:justify;" align="justify">Para ver el resultado tenemos que asegurarnos de que la nueva actividad se muestre cuando se inicie la aplicación. Eso se controla en el manifiesto de la aplicación. Tenemos dos formas de hacerlo: usando el editor visual o modificando directamente el código. Veamos como se hace con el editor:</p>
<div align="justify">
<ol>
<li>
<p style="text-align:justify;">Abrimos el archivo <code>AndroidManifest.xml</code>, si no estaba abierto.</p>
</li>
<li>
<p style="text-align:justify;">Seleccionamos la pestaña <strong>Application</strong> en la parte inferior. Tras plegar las secciones <strong>Application Toggle</strong> y <strong>Application Attributes </strong>veremos la lista de nodos con la actividad que creamos antes.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-10-actividad-en-el-editor-del-manifiesto.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Actividad en el editor del manifiesto" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-10-actividad-en-el-editor-del-manifiesto_thumb.png?w=244&#038;h=215" alt="Actividad en el editor del manifiesto" width="244" height="215" border="0" /></a></li>
<li>
<p style="text-align:justify;">Pulsamos con el botón derecho sobre la actividad en la lista y escogemos la opción <strong>Add</strong> en el menú que se despliega. Se muestra una ventana con los elementos que podemos crear en ese punto.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-11-elementos-que-se-pueden-crear-en-una-actividad.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Elementos que se pueden crear en una actividad" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-11-elementos-que-se-pueden-crear-en-una-actividad_thumb.png?w=244&#038;h=229" alt="Elementos que se pueden crear en una actividad" width="244" height="229" border="0" /></a></li>
<li>
<p style="text-align:justify;">Nos aseguramos de tener seleccionada la segunda opción, <strong>Create a new element in the selected element</strong> y luego escogemos <strong>Intent Filter</strong> en la lista de elementos disponibles. Finalmente pulsamos <strong>OK</strong>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-12-actividad-con-un-intent-filter.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Actividad con un Intent Filter" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-12-actividad-con-un-intent-filter_thumb.png?w=244&#038;h=215" alt="Actividad con un Intent Filter" width="244" height="215" border="0" /></a></li>
<li>
<p style="text-align:justify;">Ahora repetimos el mismo proceso pulsando sobre el <strong>Intent Filter</strong> con el botón derecho del ratón y escogiendo <strong>Add</strong>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-13-elementos-que-se-pueden-crear-en-un-intent-filter.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Elementos que se pueden crear en un Intent Filter" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-13-elementos-que-se-pueden-crear-en-un-intent-filter_thumb.png?w=244&#038;h=200" alt="Elementos que se pueden crear en un Intent Filter" width="244" height="200" border="0" /></a></li>
<li>
<p style="text-align:justify;">En la ventana que se abre seleccionamos <strong>Action</strong> y pulsamos <strong>OK</strong>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-14-intent-filter-con-action.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Intent Filter con Action" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-14-intent-filter-con-action_thumb.png?w=244&#038;h=215" alt="Intent Filter con Action" width="244" height="215" border="0" /></a></li>
<li>
<p style="text-align:justify;">Al elemento <strong>Action</strong> hay que ponerle un nombre. Para ello desplegamos la lista <strong>Name</strong> en la sección <strong>Attributes for Action</strong> y seleccionamos <strong>android.intent.action.MAIN</strong>.</p>
</li>
<li>
<p style="text-align:justify;">Tenemos que añadir un elemento más al Intent Filter, así que volvemos a pulsar con el botón derecho sobre <strong>Intent Filter</strong>, escogemos <strong>Add</strong>, seleccionamos <strong>Category</strong> y pulsamos <strong>OK</strong>.</p>
<p><a href="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-15-intent-filter-con-action-y-category.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Intent Filter con Action y Category" src="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-15-intent-filter-con-action-y-category_thumb.png?w=244&#038;h=215" alt="Intent Filter con Action y Category" width="244" height="215" border="0" /></a></li>
<li>
<p style="text-align:justify;">También tenemos que asignar un nombre al elemento <strong>Category</strong>, así que desplegamos la lista <strong>Name</strong> y escogemos <strong>android.intent.category.LAUNCHER</strong>.</p>
</li>
<li>
<p style="text-align:justify;">Finalmente, grabamos los cambios con <strong>File</strong> | <strong>Save</strong>.</p>
</li>
</ol>
</div>
<p style="text-align:justify;" align="justify">Si pulsamos en la última pestaña inferior, <strong>AndroidManifest.xml</strong>, podemos ver el código XML que se ha creado:</p>
<pre class="brush: xml; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">
&lt;activity android:name=&quot;IUIntroXML&quot;&gt;
   &lt;intent-filter&gt;
      &lt;action android:name=&quot;android.intent.action.MAIN&quot;&gt;&lt;/action&gt;
      &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot;&gt;&lt;/category&gt;
   &lt;/intent-filter&gt;
&lt;/activity&gt;
</pre>
<p style="text-align:justify;" align="justify">Se puede observar claramente que el código reproduce la estructura que hemos ido creando. Podemos, por tanto, conseguir lo mismo añadiendo esas mismas líneas (el <strong>&lt;intent-filter&gt;</strong> y su contenido) a cualquier actividad que tengamos en la aplicación. Además, aunque lo habitual es que sólo una de ellas esté configurada para ser actividad de inicio, podemos tener este Intent Filter en varias actividades a la vez. En esta situación, cualquiera de las actividades marcada con la acción <strong>MAIN</strong> puede ser la primera que se muestre al iniciar la aplicación. Y cualquier actividad con la categoría <strong>LAUNCHER</strong> tendrá un icono en el lanzador de aplicaciones del dispositivo cuando la instalemos.</p>
<h3 align="justify">Creando la interfaz de usuario por código</h3>
<p style="text-align:justify;" align="justify">Para terminar este post, veamos el código que permite crear el mismo diseño que el archivo XML mostrado arriba, pero sin utilizarlo:</p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:38c4c3b9-09c9-4461-a8ae-cbce81df4f8e" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<pre class="brush: java; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">
/** Called when the activity is first created. */
@Override
public void onCreate (Bundle savedInstanceState)
{
   super.onCreate(savedInstanceState);

   TextView etiqueta1 = new TextView(this);
   etiqueta1.setText(&quot;Esto es una etiqueta de texto&quot;);
   etiqueta1.setLayoutParams(new LayoutParams(
      LayoutParams.WRAP_CONTENT,
      LayoutParams.WRAP_CONTENT));

   Button boton1 = new Button(this);
   boton1.setText(&quot;Esto es un botón&quot;);
   boton1.setLayoutParams(new LayoutParams(
      LayoutParams.WRAP_CONTENT,
      LayoutParams.WRAP_CONTENT));

   LinearLayout principal = new LinearLayout(this);
   principal.setOrientation(LinearLayout.VERTICAL);
   principal.setLayoutParams(new LayoutParams(
      LayoutParams.FILL_PARENT,
      LayoutParams.FILL_PARENT));
   principal.addView(etiqueta1);
   principal.addView(boton1);

   setContentView(principal);
}
</pre>
</div>
<p style="text-align:justify;" align="justify">Se crea un objeto para cada una de las vistas. En el constructor se pasa la propia actividad (<strong>this</strong>) como contexto. La vista la necesita para acceder a sus recursos.</p>
<p style="text-align:justify;" align="justify">Las propiedades de cada vista se modifican con los métodos <strong>set</strong> correspondientes. Los parámetros, como ya hemos mencionado en posts anteriores, son diferentes. Se asignan mediante el método <strong>setLayoutParams</strong> utilizando una clase <strong>LayoutParams</strong>. En este caso se ha usado la versión más general, definida como clase anidada en <strong>ViewGroup</strong>, en lugar de la específica del <strong>LinearLayout</strong> (que tiene el mismo nombre: <strong>LayoutParams</strong>).</p>
<p style="text-align:justify;" align="justify">Una vez creadas las tres vistas, se añaden los widgets al diseño, en el mismo orden en que se pusieron en el archivo XML, dado que es el orden en que queremos que se muestren. Para ello se utiliza el método <strong>addView</strong> que proporciona la clase <strong>ViewGroup</strong>.</p>
<p style="text-align:justify;" align="justify">Finalmente se asigna el diseño a la actividad, utilizando una sobrecarga del mismo método <strong>setContentView</strong> que usamos para cargar el diseño XML.</p>
<p class="sticky" style="text-align:center;" align="center">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong></p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2011/10/09/diseando-interfaces-en-android-codificacin/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">730</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-01-ejemplo-de-diseo-en-xml.png" medium="image">
			<media:title type="html">Ejemplo de diseño en XML</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-02-editor-del-manifiesto-de-la-aplicacin-android_thumb.png" medium="image">
			<media:title type="html">Editor del manifiesto de la aplicación Android</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-03-seleccin-del-tipo-de-nodo-de-aplicacin-a-crear_thumb.png" medium="image">
			<media:title type="html">Selección del tipo de nodo de aplicación a crear</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-04-manifiesto-atributos-de-la-actividad_thumb.png" medium="image">
			<media:title type="html">Manifiesto - Atributos de la actividad</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-05-nueva-clase-java_thumb.png" medium="image">
			<media:title type="html">Nueva clase Java</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-06-cdigo-predeterminado-de-una-actividad_thumb.png" medium="image">
			<media:title type="html">Código predeterminado de una actividad</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-07-elementos-disponibles-en-eclipse_thumb.png" medium="image">
			<media:title type="html">Elementos disponibles en Eclipse</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-08-nuevo-archivo-xml-para-android_thumb.png" medium="image">
			<media:title type="html">Nuevo archivo XML para Android</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-09-editor-grfico-de-diseos_thumb.png" medium="image">
			<media:title type="html">Editor gráfico de diseños</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-10-actividad-en-el-editor-del-manifiesto_thumb.png" medium="image">
			<media:title type="html">Actividad en el editor del manifiesto</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-11-elementos-que-se-pueden-crear-en-una-actividad_thumb.png" medium="image">
			<media:title type="html">Elementos que se pueden crear en una actividad</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-12-actividad-con-un-intent-filter_thumb.png" medium="image">
			<media:title type="html">Actividad con un Intent Filter</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-13-elementos-que-se-pueden-crear-en-un-intent-filter_thumb.png" medium="image">
			<media:title type="html">Elementos que se pueden crear en un Intent Filter</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-14-intent-filter-con-action_thumb.png" medium="image">
			<media:title type="html">Intent Filter con Action</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/10/0032-15-intent-filter-con-action-y-category_thumb.png" medium="image">
			<media:title type="html">Intent Filter con Action y Category</media:title>
		</media:content>
	</item>
		<item>
		<title>Recursos en Android: dimensiones</title>
		<link>https://columna80.wordpress.com/2011/10/03/recursos-en-android-dimensiones/</link>
					<comments>https://columna80.wordpress.com/2011/10/03/recursos-en-android-dimensiones/#respond</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Mon, 03 Oct 2011 18:40:48 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Recursos]]></category>
		<category><![CDATA[Vistas]]></category>
		<category><![CDATA[XML]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=685</guid>

					<description><![CDATA[Las dimensiones son recursos XML que sirven para especificar tamaños de elementos de la interfaz de usuario de más formas que simplemente en píxeles, que sería lo habitual. Están formadas por un valor numérico con decimales (float) y una cadena de texto de dos caracteres que representa la unidad en la que se expresa el [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;" align="justify">Las dimensiones son recursos XML que sirven para especificar tamaños de elementos de la interfaz de usuario de más formas que simplemente en píxeles, que sería lo habitual.</p>
<p style="text-align:justify;" align="justify">Están formadas por un valor numérico con decimales (<strong>float</strong>) y una cadena de texto de dos caracteres que representa la unidad en la que se expresa el valor numérico. En el archivo XML ambos datos se escriben juntos, en una sola cadena de texto, sin espacio o separadores entre ellos.</p>
<p style="text-align:justify;" align="justify">La ventaja que representan es que la mayoría de las unidades son relativas, tanto a características físicas del dispositivo en el que se están utilizando, como a diversos elementos de estilo que estén activos en un momento dado. Esto permite que unos mismos valores utilizados en un diseño sean traducidos a tamaños diferentes en cada dispositivo en que se ejecute la aplicación, de forma que la experiencia del usuario sea similar.</p>
<p style="text-align:justify;" align="justify">Si usáramos siempre medidas expresadas en píxeles podría ocurrir que un elemento que tiene un tamaño adecuado para su uso en un dispositivo en particular se viera demasiado pequeño en otro dispositivo con mayor densidad de píxeles (cantidad de píxeles por cada pulgada de pantalla).</p>
<p style="text-align:justify;" align="justify">Queda claro que las dimensiones las vamos a utilizar bastante, así que veamos cómo hacerlo.</p>
<p><span id="more-685"></span></p>
<h3 align="justify">Unidades</h3>
<p style="text-align:justify;" align="justify">Las que se enumeran a continuación son las diferentes unidades que podemos utilizar para definir dimensiones:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><strong><code>dp</code> (píxeles independientes de la densidad)</strong>: es una unidad abstracta que se basa en la densidad de píxeles de la pantalla. Sirve para garantizar que las cosas tienen las mismas medidas físicas en cualquier pantalla. Como regla, hay que tener en cuenta que <code>160dp</code> equivaldrá a una pulgada (o, lo que es lo mismo, <code>63dp</code> serán un centímetro) en cualquier pantalla (en teoría, al menos).</p>
</li>
<li>
<p style="text-align:justify;"><strong><code>sp</code> (píxeles independientes de la escala)</strong>: es igual que la unidad <strong><code>dp</code></strong>, pero escalada según el tamaño de fuente escogido por el usuario. Es la unidad recomendada para definir el tamaño de los textos que se muestran en pantalla.</p>
</li>
<li>
<p style="text-align:justify;"><strong><code>pt</code> (puntos)</strong>: representan 1/72 partes de una pulgada (o, más o menos, 1/28 de un centímetro) en cualquier pantalla.</p>
</li>
<li>
<p style="text-align:justify;"><strong><code>px</code> (píxeles)</strong>: no se recomienda utilizar esta unidad, porque las pantallas tienen diferentes densidades y tamaños, por lo que los elementos dimensionados en píxeles se pueden ver de formas muy diferentes.</p>
</li>
<li>
<p style="text-align:justify;"><strong><code>mm</code> (milímetros)</strong>: medida directa del elemento en pantalla, en unidades más internacionales.</p>
</li>
<li>
<p style="text-align:justify;"><strong><code>in</code> (pulgadas)</strong>: medida directa del elemento en pantalla, en unidades anglosajonas.</p>
</li>
</ul>
</div>
<h3>Uso de dimensiones en XML</h3>
<p style="text-align:justify;" align="justify">Las dimensiones se pueden utilizar directamente en los atributos en forma de cadena de texto. Por ejemplo:</p>
<pre class="brush: xml; auto-links: false; gutter: false; highlight: [4]; pad-line-numbers: true; title: ; notranslate">
&lt;EditText
   android:layout_width=&quot;wrap_content&quot;
   android:layout_height=&quot;wrap_content&quot;
   android:minWidth=&quot;160sp&quot; /&gt;
</pre>
<p style="text-align:justify;" align="justify">Sin embargo es muy frecuente utilizar la misma dimensión para más de una vista, por lo que resulta más práctico usar un archivo de recursos. Como las dimensiones son recursos simples, el archivo habrá que crearlo en <code>res/values</code>. La sintaxis básica es la siguiente:</p>
<pre class="brush: xml; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
   &lt;dimen name=&quot;nombre_de_la_dimensión&quot;&gt;valor&lt;/dimen&gt;
&lt;/resources&gt;
</pre>
<p style="text-align:justify;">El nombre es el identificador que usaremos en los atributos a los que queramos asignarles la dimensión y el valor es la cadena que habríamos usado directamente (pero sin comillas). Por ejemplo:</p>
<pre class="brush: xml; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
   &lt;dimen name=&quot;cuadros_texto&quot;&gt;160sp&lt;/dimen&gt;
&lt;/resources&gt;
</pre>
<p style="text-align:justify;" align="justify">Podemos definir más de una dimensión en un mismo archivo XML, simplemente añadiendo más elementos <strong>&lt;dimen&gt;</strong> dentro de <strong>&lt;resources&gt;</strong>. Para usarlas luego en atributos se utiliza el nombre asignado a la dimensión (que actúa de <a href="https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades#identificadores">identificador</a>):</p>
<pre class="brush: xml; auto-links: false; gutter: false; highlight: [4]; pad-line-numbers: true; title: ; notranslate">
&lt;EditText
   android:layout_width=&quot;wrap_content&quot;
   android:layout_height=&quot;wrap_content&quot;
   android:minWidth=&quot;@dimen/cuadros_texto&quot; /&gt;
</pre>
<h3>Usar dimensiones en Java</h3>
<p>Si definimos dimensiones en un archivo XML de recursos, el compilador añadirá las constantes correspondientes a la clase <strong>R</strong>, tal y como hace con los identificadores de las vistas. Podemos utilizar estas constantes para acceder a las dimensiones desde el código utilizando el método <strong>getDimensionPixelSize</strong> de la clase <strong>Resources</strong>. Se haría así:</p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:21b5b846-dc83-4caa-a902-8770391ca5c8" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<pre class="brush: java; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">
EditText et = new EditText(this);
et.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Resources res = getResources();
et.setMinimumWidth(res.getDimensionPixelSize(R.dimen.cuadros_texto));
</pre>
</div>
<p style="text-align:justify;" align="justify">Primero hay que obtener un objeto de la clase <strong>Resources</strong>. El método <strong>getResources</strong> que la clase <strong>Activity</strong> hereda de <strong>Context</strong> lo proporciona. Este objeto contiene la información necesaria sobre la pantalla en la que se muestra la actividad como para poder convertir cualquier dimensión relativa en un valor en píxeles, que es lo que esperan la mayoría de los métodos.</p>
<p style="text-align:justify;" align="justify">La clase <strong>Resources</strong> tiene también un método <strong>getDimension</strong> que devuelve la misma información. La diferencia es que el método <strong>getDimensionPixelSize</strong> procesa el valor que devuelve <strong>getDimension</strong> para que se pueda usar con seguridad como tamaño. Hace dos cosas: redondear el valor devuelto por <strong>getDimension</strong> y, si el valor resultante es cero, sustituirlo por 1.</p>
<p style="text-align:justify;" align="justify">Por otro lado, también es posible utilizar dimensiones en Java sin definirlas previamente en XML. El siguiente ejemplo sería equivalente al que hemos visto antes:</p>
<div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:45a1066b-9f01-4c08-bd33-947d354d0750" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<pre class="brush: java; auto-links: false; gutter: false; pad-line-numbers: true; title: ; notranslate">EditText et = new EditText(this);
et.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
int valor = (int) TypedValue.applyDimension(
   TypedValue.COMPLEX_UNIT_SP,
   (float) 160,
   getResources().getDisplayMetrics());
et.setMinimumWidth(valor);
</pre>
</div>
<p style="text-align:justify;" align="justify">El método <strong>applyDimension</strong> de la clase <strong>TypedValue</strong> permite convertir una dimensión en su equivalente en píxeles según el contexto actual (el contexto contiene, básicamente, las características de la pantalla donde se va a mostrar la actividad).</p>
<p style="text-align:justify;" align="justify"><strong>TypedValue</strong> es una clase que permite crear objetos con tipos dinámicos, por lo que comúnmente se utiliza para almacenar recursos XML en Java. La clase incluye una serie de constantes que permiten asociar un tipo a un valor numérico, como las unidades en el caso de las dimensiones. En el ejemplo hemos utilizado la constante <strong>COMPLEX_UNIT_SP</strong> para indicar que el valor 160 que le pasamos al método <strong>applyDimension</strong> está expresado en píxeles independientes de la escala.</p>
<p style="text-align:justify;" align="justify">Como se puede ver, podemos utilizar dimensiones sea cual sea la forma en que escojamos crear nuestras interfaces de usuario, por lo que no hay excusas para no aprovechar este recurso que nos ayuda a que nuestra aplicación se vea como realmente queremos en cualquier tipo de dispositivo.</p>
<p class="sticky" style="text-align:center;" align="center">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2011/10/03/recursos-en-android-dimensiones/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">685</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>
	</item>
		<item>
		<title>Dise&#241;ando interfaces en Android: padding y margen</title>
		<link>https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/</link>
					<comments>https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/#respond</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Sun, 25 Sep 2011 19:00:45 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Actividades]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[Vistas]]></category>
		<category><![CDATA[Widgets]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=680</guid>

					<description><![CDATA[Al diseñar una interfaz de usuario, una de las cosas de la que nos damos cuenta en seguida es que las vistas que colocamos tienden a colocarse demasiado cerca unas de otras. Si utilizamos wrap_content para que el tamaño de la vista se ajuste al contenido (algo bastante habitual), nos encontramos con frecuencia con textos [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;" align="justify">Al diseñar una interfaz de usuario, una de las cosas de la que nos damos cuenta en seguida es que las vistas que colocamos tienden a colocarse demasiado cerca unas de otras. Si utilizamos <code><strong>wrap_content</strong></code> para que el tamaño de la vista se ajuste al contenido (algo bastante habitual), nos encontramos con frecuencia con textos excesivamente pegados unos a otros, elementos demasiado cerca de los bordes, etc.</p>
<p style="text-align:justify;" align="justify">Echamos en falta rápidamente una forma de dejar algo de espacio entre las vistas o de alejar su contenido de los bordes. Y para ello Android nos proporciona dos tipos de propiedades, padding y margen (<em>margin</em>). Las dos tienen una función similar, pero la realizan de diferente forma. La principal diferencia es que el padding forma parte de la vista y el margen del diseño. Este detalle, aparte de influir sobre en qué clase se incluyen las propiedades, determina dónde se sitúa ese espacio adicional que añaden. Mientras que el padding es un espacio situado entre el borde de la vista y su contenido, el margen se sitúa entre el borde de la vista y los bordes de los elementos que la rodean o del diseño que la contiene.</p>
<p style="text-align:justify;" align="justify">Seguramente quede más claro con la siguiente captura:</p>
<p align="justify"><a href="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-01-diferencia-entre-padding-y-margen.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="Diferencia entre padding y margen" src="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-01-diferencia-entre-padding-y-margen_thumb.png?w=324&#038;h=245" alt="Diferencia entre padding y margen" width="324" height="245" border="0" /></a></p>
<p style="text-align:justify;" align="justify">El fondo (<em>background</em>) de todos los <strong>TextView</strong> de esta interfaz se ha establecido en verde, por lo que cada recuadro verde muestra el área total que está ocupando la vista, sus límites. Se puede observar como, si no utilizamos ni padding ni margen (segunda fila), el tamaño de cada vista se ajusta completamente al contenido y las vistas quedan totalmente pegadas unas a otras. Cuando usamos padding (filas 1 y 3) añadimos un espacio entre el texto y los límites de la vista (espacio que se rellena con el fondo). Por su parte, el margen (filas 1 y 4) agrega ese espacio alrededor de los límites de la vista pero por fuera de ella, provocando que las vistas se separen unas de otras y de los bordes de los <strong>LinearLayout</strong> que las contienen (y permitiendo que se vea el fondo del diseño, azul o rojo en la interfaz de ejemplo). Finalmente, la captura también demuestra que se pueden utilizar las dos propiedades a la vez (fila 1) y el resultado que proporcionan.</p>
<p style="text-align:justify;" align="justify">El padding es una propiedad de las vistas, como vimos en un <a href="https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/">post anterior</a>. El margen, al ser externo a las vistas, se deja en mano de los contenedores de vistas, por lo que se implementa como <a href="https://columna80.wordpress.com/2011/09/20/diseando-interfaces-en-android-parmetros/">parámetro de los diseños</a>. Sin embargo ambas se utilizan de forma muy similar. Veamos cómo:</p>
<p><span id="more-680"></span></p>
<h3 align="justify">Padding</h3>
<p style="text-align:justify;" align="justify">El padding, como propiedad de la clase <strong>View</strong>, es compartida por todas las vistas, ya sean widgets o diseños. Está formada, en realidad, por cuatro propiedades, una para cada lateral de la vista. En XML se accede a estas propiedades mediante los atributos <strong>android:paddingLeft</strong>, <strong>android:paddingRight</strong>, <strong>android:paddingTop</strong> y <strong>android:paddingBottom</strong> de las vistas. Estos atributos permiten establecer un valor distinto para cada uno de los laterales o dejar alguno sin asignar. De forma predeterminada, cada una de estas propiedades tiene el valor cero.</p>
<p style="text-align:justify;" align="justify">En el diseño XML tenemos disponible también el atributo <strong>android:padding</strong>, que permite establecer el padding de todos los laterales a la vez. Este atributo nos permite ahorrar código cuando queremos que el padding de los cuatro laterales tenga el mismo tamaño.</p>
<p style="text-align:justify;" align="justify">Para modificar el padding por código disponemos del método <strong>setPadding</strong> (definido en la clase <strong>View</strong>). Este método recibe obligatoriamente cuatro valores, que se corresponden con los laterales izquierdo, superior, derecho e inferior, respectivamente. No disponemos de sobrecargas del método <strong>setPadding</strong>, por lo que siempre tendremos que especificar los cuatro valores cuando asignemos el padding desde Java.</p>
<p style="text-align:justify;" align="justify">No es la única diferencia entre el uso del padding desde XML y desde Java. Los atributos XML tienen un valor de tipo <em>dimensión</em>. Las dimensiones son un tipo de recurso que incluyen un valor numérico y una unidad. Esto permite definir el padding en términos de píxeles, de medidas físicas como milímetros o pulgadas o incluso de medidas abstractas relativas a la densidad de píxeles de la pantalla o al tamaño de la fuente que se utiliza en la vista. Para más detalles, consulta <a title="Recursos en Android: dimensiones" href="https://columna80.wordpress.com/2011/10/03/recursos-en-android-dimensiones/">este post</a>.</p>
<p style="text-align:justify;" align="justify">Sin embargo, los parámetros del método <strong>setPadding</strong> son de tipo <strong>int</strong> y no admiten unidades. Así, en Java sólo se puede establecer el padding en píxeles. No obstante, también hay una forma de calcular en Java los píxeles a los que equivale cualquier dimensión. Lo veremos en un próximo post.</p>
<p style="text-align:justify;" align="justify">La clase View dispone también de los métodos <strong>getPaddingLeft</strong>, <strong>getPaddingRight</strong>, <strong>getPaddingTop</strong> y <strong>getPaddingBottom</strong>, que permiten obtener el padding actual de cada lateral de la vista, en píxeles. Hay que tener en cuenta que algunas vistas pueden dejar un espacio adicional para una barra de desplazamiento (suponiendo que la vista admita el uso de barras de desplazamiento y se esté utilizando un estilo para las mismas que requiera espacio adicional). Si es el caso, el valor devuelto por estos métodos <strong>get</strong> puede no corresponderse con el establecido mediante los atributos XML o el método <strong>setPadding</strong>.</p>
<h3 align="justify">Margen</h3>
<p style="text-align:justify;" align="justify">Como ya hemos visto, los márgenes son externos a la vista a la que se le aplican. Por lo tanto, no es de extrañar que no sean propiedades de la clase View como ocurre con el padding. En lugar de eso, son parámetros de los diseños.</p>
<p style="text-align:justify;" align="justify">En un post anterior vimos que los diseños comparten unos parámetros básicos que se definen en la clase <strong>ViewGroup.LayoutParams</strong>. También que cada diseño define su propia clase <strong>LayoutParams</strong> que hereda de la de <strong>ViewGroup</strong>. Lo que no mencioné es que esa herencia no es directa.</p>
<p style="text-align:justify;" align="justify">Dentro de la clase <strong>ViewGroup</strong> se define otra clase con parámetros. Se trata de <strong>MarginLayoutParams</strong>. Esta clase hereda a su vez de <strong>ViewGroup.LayoutParams</strong>. Las clases de parámetros que se definen en los diseños heredan (directa o indirectamente) de esta clase <strong>MarginLayoutParams</strong>. De esta forma se agregan los márgenes a los parámetros básicos que comparten todos los diseños.</p>
<p style="text-align:justify;" align="justify">Al igual que con el resto de parámetros de diseño, los atributos XML correspondientes se aplican sobre las vistas contenidas en el diseño como si fueran propiedades propias. Y, de igual forma, los atributos de <strong>MarginLayoutParams</strong> también se distinguen mediante el prefijo <strong>layout_</strong>.</p>
<p style="text-align:justify;" align="justify">Para establecer los márgenes de cada vista, la clase <strong>MarginLayoutParams</strong> proporciona los atributos <strong>android:layout_marginLeft</strong>, <strong>android:layout_marginRight</strong>, <strong>android:layout_marginTop</strong> y <strong>android:layout_marginBottom</strong>. Al igual que con el padding, estos atributos permiten establecer valores de margen diferentes para cada lateral de la vista. También en este caso tenemos un atributo <strong>android:layout_margin</strong> que permite establecer el mismo valor para el margen de los cuatro laterales a la vez.</p>
<p style="text-align:justify;" align="justify">Siguiendo con las similitudes, la clase <strong>MarginLayoutParams</strong> proporciona un método <strong>setMargins</strong> que permite asignar valores a los márgenes de los laterales izquierdo, superior, derecho e inferior de la vista. Por supuesto, todo lo explicado sobre dimensiones y valores en píxeles para el padding se aplica exactamente igual para el margen.</p>
<p class="sticky" style="text-align:center;" align="center">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">680</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-01-diferencia-entre-padding-y-margen_thumb.png" medium="image">
			<media:title type="html">Diferencia entre padding y margen</media:title>
		</media:content>
	</item>
		<item>
		<title>Dise&#241;ando interfaces en Android: par&#225;metros</title>
		<link>https://columna80.wordpress.com/2011/09/20/diseando-interfaces-en-android-parmetros/</link>
					<comments>https://columna80.wordpress.com/2011/09/20/diseando-interfaces-en-android-parmetros/#respond</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Tue, 20 Sep 2011 19:44:43 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Vistas]]></category>
		<category><![CDATA[Widgets]]></category>
		<category><![CDATA[XML]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=666</guid>

					<description><![CDATA[En el post anterior vimos cómo se crean diseños en XML y cómo los atributos que tenemos disponibles en XML se corresponden, de forma más o menos directa, con métodos de las clases Java que implementan las vistas. También hemos visto algunas de las propiedades más comunes de las vistas, que heredan tanto widgets como [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;" align="justify">En el <a href="https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/">post anterior</a> vimos cómo se crean diseños en XML y cómo los atributos que tenemos disponibles en XML se corresponden, de forma más o menos directa, con métodos de las clases Java que implementan las vistas. También hemos visto algunas de las propiedades más comunes de las vistas, que heredan tanto <a href="https://columna80.wordpress.com/2011/09/12/las-vistas-android-diseos-y-widgets/">widgets como diseños</a>.</p>
<p style="text-align:justify;" align="justify">En este post vamos a profundizar algo más en los diseños viendo, sobre todo, qué cosas tienen en común, antes de entrar en detalles particulares de cada uno de los tipos que tenemos disponibles.</p>
<p><span id="more-666"></span></p>
<h3 align="justify">Diseños</h3>
<p style="text-align:justify;" align="justify">A diferencia de la mayoría de los widgets, los diseños no heredan directamente de la clase <strong>View</strong>, sino que heredan de la clase <strong>ViewGroup</strong> que, a su vez, hereda de <strong>View</strong>. De esta forma, los diseños tienen todas las propiedades de las vistas (puesto que son también vistas) y, al mismo tiempo, heredan todo lo que ofrece <strong>ViewGroup</strong>.</p>
<p style="text-align:justify;" align="justify"><strong>ViewGroup</strong> no es sólo la clase madre de los diseños, sino que aparece entre los ancestros de cualquier vista que pueda contener a otras, aunque no sean propiamente diseños. Esto conviene aclararlo. Llamamos diseños a las vistas que no sólo pueden contener otras vistas, sino que, además, se encargan de distribuirlas en la actividad, controlando su posición y dimensiones, de acuerdo a unas reglas establecidas.</p>
<p style="text-align:justify;" align="justify">Sin embargo hay otras vistas, como <strong>ListView</strong>, <strong>Gallery</strong> o <strong>DatePicker</strong>, que también contienen otras vistas. Lo que ocurre es que en estos casos, los tipos de vistas que pueden contener o la forma en que se distribuyen está muy limitada o es fija. Los diseños son bastante más flexibles.</p>
<p style="text-align:justify;" align="justify">Al igual que la clase <strong>View</strong>, la propia clase <strong>ViewGroup</strong> también proporciona algunas propiedades a los diseños. Sin embargo, no son propiedades que se utilicen con frecuencia por lo que no hablaré de ellas por el momento.</p>
<h4 align="justify">Los parámetros de los diseños</h4>
<p style="text-align:justify;" align="justify">De lo que sí voy a hablar ahora es de una clase que se define dentro de la clase <strong>ViewGroup</strong> y que tiene suma importancia: <strong>ViewGroup.LayoutParams</strong>. Esta clase también define propiedades que luego se pueden usar como atributos en los archivos XML donde se definen los diseños. La diferencia radica en que estos atributos no se aplican sobre los diseños, sino sobre las vistas que contienen.</p>
<blockquote>
<p align="justify"><strong>Nota</strong></p>
<p style="text-align:justify;" align="justify"><em>El compilador nos permite asignar valores a estos parámetros por medio de atributos en las etiquetas de las vistas como si fueran propiedades propias. Pero no debemos olvidar que siguen siendo parámetros del diseño y que es éste el que condiciona cuáles tenemos disponibles en cada caso.</em></p>
<p style="text-align:justify;" align="justify"><em>Podemos tener, por ejemplo, dos <strong>Button</strong> idénticos, uno en un <strong>RelativeLayout</strong> y otro en un <strong>LinearLayout</strong>. Si el parámetro <strong>alignTop</strong> sólo está definido en el diseño <strong>RelativeLayout</strong>, el atributo correspondiente, <strong>android:layout_alignTop</strong>, sólo lo podremos usar en el <strong>&lt;Button&gt;</strong> que esté dentro del <strong>&lt;RelativeLayout&gt;</strong> y no en el otro.</em></p>
</blockquote>
<p style="text-align:justify;" align="justify">El compilador recopila los valores de todos estos atributos y los encapsula en un objeto de esta clase <strong>ViewGroup.LayoutParams</strong>. Luego asigna ese objeto a la vista mediante el método <strong>setLayoutParams</strong>. Este método se define en la clase <strong>View</strong>, por lo que todas las vistas lo heredan. Posteriormente, el diseño recupera los valores de estos parámetros de las vistas y los utiliza para calcular dónde debe situar cada una de ellas y con qué dimensiones.</p>
<p style="text-align:justify;" align="justify">Todo esto nos proporciona una forma sencilla de asociar a cada vista la información necesaria para que el diseño que la contiene trabaje con ella. Y, aún más, el mecanismo de herencia de Java permite que cada diseño proporcione sus parámetros particulares haciendo que estén disponibles para todas las vistas que se incluyan en él.</p>
<p style="text-align:justify;" align="justify">Cada diseño, además de heredar de <strong>ViewGroup</strong>, también proporcionará su propia clase <strong>LayoutParams</strong>, cada una de las cuales heredará de <strong>ViewGroup.LayoutParams</strong>. Para seguir el mismo esquema, estas clases estarán definidas dentro de la clase que implementa el diseño. Por ejemplo, el diseño <strong>RelativeLayout</strong> tendrá asociada una clase <strong>RelativeLayout.LayoutParams</strong>.</p>
<p style="text-align:justify;" align="justify">Como estas clases heredan de <strong>ViewGroup.LayoutParams</strong>, dispondrán de entrada de todos los parámetros que se definen aquí. Además, las propiedades de la herencia en Java nos permiten asignar objetos de una clase hija a variables de la clase madre. Esto significa que se puede utilizar el método <strong>setLayoutParams</strong> de la clase <strong>View</strong> (disponible en todas las vistas) para asignar un objeto de una clase derivada de <strong>ViewGroup.LayoutParams</strong> como, por ejemplo, <strong>RelativeLayout.LayoutParams</strong>.</p>
<p style="text-align:justify;" align="justify">De esta forma podemos tener los parámetros particulares de cualquier diseño disponibles en todas las vistas. El compilador se encargará del resto, permitiéndonos usar los atributos XML relacionados en cada vista que incluyamos en el diseño.</p>
<h4 align="justify">Las dimensiones de una vista</h4>
<p style="text-align:justify;" align="justify">Ya hemos visto que los parámetros que se definen en <strong>ViewGroup.LayoutParams</strong> van a formar parte de los parámetros de todos los diseños, pero ¿cuáles son esos parámetros?</p>
<p style="text-align:justify;" align="justify">Pues básicamente dos: ancho y alto, representados por los atributos XML <strong>android:layout_width</strong> y <strong>android:layout_height</strong>.</p>
<blockquote>
<p align="justify"><em><strong>Nota</strong></em></p>
<p style="text-align:justify;" align="justify"><em>El prefijo <strong>layout_</strong> es una forma de distinguir los atributos propios de las vistas de los parámetros de los diseños. </em><em>Las ayudas a la codificación del editor en Eclipse nos permiten saber qué parámetros tenemos disponibles en cada vista concreta escribiendo <strong>android:layout_</strong> y pulsando <strong>Ctrl</strong> + <strong>Espacio</strong>:<br />
</em><a href="https://columna80.wordpress.com/wp-content/uploads/2011/09/0029-01-asistencia-contextual-para-archivos-xml-en-eclipse.png" target="_blank"><br />
<img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:block;float:none;padding-top:0;border-width:0;margin:5px auto;" title="0029.01 - Asistencia contextual para archivos XML en Eclipse" src="https://columna80.wordpress.com/wp-content/uploads/2011/09/0029-01-asistencia-contextual-para-archivos-xml-en-eclipse_thumb.png?w=644&#038;h=214" alt="0029.01 - Asistencia contextual para archivos XML en Eclipse" width="644" height="214" border="0" /></a></p>
</blockquote>
<p style="text-align:justify;" align="justify">El objetivo de estos dos parámetros es proporcionar a las vistas una forma de indicar cuáles deben ser sus dimensiones en relación al diseño que las contiene. Todas las vistas están obligadas a definirlos, dado que el diseño no podría visualizarlas sin esta información. Se les puede asignar un valor de tipo dimensión o una de las constantes predefinidas.</p>
<p style="text-align:justify;" align="justify">Una dimensión es un valor numérico que va acompañado de una cadena de texto que indica la unidad en la que se expresa dicho valor numérico. Por ejemplo, «<code>20px</code>» significa 20 píxeles y «<code>10mm</code>» indica 10 milímetros. Puedes ver más detalles sobre las dimensiones y las unidades que tenemos disponibles en <a title="Recursos en Android: dimensiones" href="https://columna80.wordpress.com/2011/10/03/recursos-en-android-dimensiones/">este post</a>. Por el momento nos basta con saber que asignar una dimensión a uno de estos atributos sirve para especificar un tamaño fijo para el ancho o el alto de la vista.</p>
<p style="text-align:justify;" align="justify">Fijar el tamaño de las vistas no suele ser muy recomendable si pretendemos que nuestra aplicación se vea bien en todo tipo de pantallas. Para estas situaciones disponemos de dos constantes que le dicen al diseño cómo debe dimensionar la vista sin dar valores exactos:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><strong><code>fill_parent</code></strong>: indica que queremos que el ancho o el alto de la vista se ajuste al tamaño del diseño, ocupando todo el espacio disponible en la dirección correspondiente (horizontal o vertical). Hay que tener en cuenta que esto no significa que el ancho o el alto de la vista vaya a ser exactamente el mismo que el del diseño. Si el diseño tiene definido un padding, la vista lo respetará aunque usemos <strong><code>fill_parent</code></strong>.</p>
</li>
<li>
<p style="text-align:justify;"><strong><code>wrap_content</code></strong>: con esta constante indicamos que queremos que el diseño establezca para la vista un ancho o alto que sea suficiente para mostrar su contenido. Para ello el sistema calcula cuánto espacio necesita para mostrar el contenido asignado. Por ejemplo, si la vista es un <strong>TextView</strong>, tendrá que determinar qué espacio necesita para mostrar la cadena de texto asignada teniendo en cuenta la fuente que se va a utilizar y su tamaño.</p>
</li>
</ul>
</div>
<blockquote>
<p align="justify"><strong>Un apunte sobre <code>fill_parent</code></strong></p>
<p style="text-align:justify;" align="justify"><em>Desde la versión 8 de la API de Android, que se corresponde con la versión 2.2 del sistema operativo, la constante <strong><code>fill_parent</code></strong> se considera obsoleta (</em>deprecated<em>). En su lugar hay que utilizar <strong><code>match_parent</code></strong>. Es simplemente un cambio de nombre, la funcionalidad es la misma. </em></p>
<p style="text-align:justify;" align="justify"><em>Esto significa que si programamos con versiones anteriores de la API tenemos que utilizar obligatoriamente <strong><code>fill_parent</code></strong> y que si lo hacemos con la 8 o posterior deberíamos usar <strong><code>match_parent</code></strong>, aunque podemos seguir usando <strong><code>fill_parent</code></strong> hasta que una futura versión de la API la elimine.</em></p>
<p style="text-align:justify;" align="justify"><em>En cualquier caso, como el valor de ambas constantes es el mismo, usar <em><strong><code>match_parent</code></strong></em> no impedirá en ningún caso el correcto funcionamiento de la aplicación en una versión de Android anterior a la 2.2.</em></p>
</blockquote>
<p style="text-align:justify;" align="justify">Hay que tener en cuenta que estos parámetros no son los únicos atributos que usa el diseño para decidir las dimensiones de las vistas. Hay otros atributos, como <strong>android:minWidth</strong> y <strong>android:minHeight</strong> que también se tienen en cuenta. Esto sirve, por ejemplo, si usamos la constante <strong>wrap_content</strong> con el ancho de un <strong>EditText</strong>, que no suele tener una cadena asignada. Si no definimos un ancho mínimo con <strong>android:minWidth</strong>, el diseño mostrará una vista realmente pequeña:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-01-edittext-con-wrap_content-y-sin-minwidth.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:5px;" title="EditText con WRAP_CONTENT y sin minWidth" src="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-01-edittext-con-wrap_content-y-sin-minwidth_thumb.png?w=164&#038;h=244" alt="EditText con WRAP_CONTENT y sin minWidth" width="164" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-02-edittext-con-wrap_content-y-con-minwidth.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:5px;" title="EditText con WRAP_CONTENT y con minWidth" src="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-02-edittext-con-wrap_content-y-con-minwidth_thumb.png?w=164&#038;h=244" alt="EditText con WRAP_CONTENT y con minWidth" width="164" height="244" border="0" /></a></p>
<h3 align="justify">Anidación de diseños</h3>
<p style="text-align:justify;" align="justify">En realidad decidir el tamaño de cada vista es algo bastante más complejo, y no sólo porque algunos diseños añaden numerosos parámetros a tener en cuenta a la hora de determinar dónde y con qué tamaño colocar cada vista. También está el hecho de que los diseños se pueden incluir unos dentro de otros, a distintos niveles de profundidad y mezclándose con widgets en cada uno de ellos. Esto da lugar a una estructura de árbol donde la raíz es el primer diseño que se añade a la actividad y que se puede extender por numerosas ramas.</p>
<p style="text-align:justify;" align="justify">Todo esto obliga al sistema a realizar varios recorridos por este árbol, recogiendo información de cada diseño y widget y relacionándola entre sí, para acabar asignando unas coordenadas y unas dimensiones a cada una de las vistas. Algo imprescindible para poder mostrar la actividad.</p>
<p style="text-align:justify;" align="justify">Por ejemplo, un diseño también puede usar la constante <strong><code>wrap_content</code></strong> en sus propios atributos. En este caso, para poder determinar el tamaño del diseño es necesario conocer primero el de las vistas que contiene. Para ello hay que ir descendiendo en el árbol hasta llegar a vistas con tamaño fijo o determinable directamente a partir de sus propiedades. Una vez asignado el tamaño de las hojas se puede recorrer el árbol hacia arriba para asignar el de las ramas.</p>
<p style="text-align:justify;" align="justify">Pero no siempre es tan sencillo. Los atributos que sólo determinan tamaños mínimos requieren conocer qué otras vistas compiten por el espacio y qué dimensiones pretenden tener para determinar qué tamaño se asigna finalmente a cada una. Esto obliga a hacer otra pasada más por todo el árbol.</p>
<p style="text-align:justify;" align="justify">El objetivo de explicar todo esto es que comprendas que los diseños que escojas y la cantidad de niveles en que los anides pueden tener un impacto tremendo en el tiempo que se tarda en mostrar la actividad. Hay muchas situaciones en las que se puede conseguir la misma interfaz de usuario utilizando menos diseños o usando otros más óptimos. Para saber qué utilizar en cada caso hay que conocer a fondo cada diseño. Por eso dedicaré en breve unos cuantos posts a hablar sobre cada uno de los diseños disponibles en la API de Android. También publicaré más adelante otro post sobre optimización de interfaces de usuario.</p>
<p class="sticky" style="text-align:center;" align="center">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2011/09/20/diseando-interfaces-en-android-parmetros/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">666</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/09/0029-01-asistencia-contextual-para-archivos-xml-en-eclipse_thumb.png" medium="image">
			<media:title type="html">0029.01 - Asistencia contextual para archivos XML en Eclipse</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-01-edittext-con-wrap_content-y-sin-minwidth_thumb.png" medium="image">
			<media:title type="html">EditText con WRAP_CONTENT y sin minWidth</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/09/0030-02-edittext-con-wrap_content-y-con-minwidth_thumb.png" medium="image">
			<media:title type="html">EditText con WRAP_CONTENT y con minWidth</media:title>
		</media:content>
	</item>
		<item>
		<title>Dise&#241;ando interfaces en Android: XML y propiedades</title>
		<link>https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/</link>
					<comments>https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/#comments</comments>
		
		<dc:creator><![CDATA[Ángel J. Vico]]></dc:creator>
		<pubDate>Sat, 17 Sep 2011 10:35:29 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Desarrollo]]></category>
		<category><![CDATA[Diseños]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[Vistas]]></category>
		<category><![CDATA[Widgets]]></category>
		<category><![CDATA[XML]]></category>
		<guid isPermaLink="false">http://columna80.wordpress.com/?p=625</guid>

					<description><![CDATA[En posts anteriores vimos de qué elementos disponemos en Android para diseñar las interfaces de usuario de nuestras aplicaciones. Por un lado tenemos actividades para crear cada una de las diferentes pantallas, y vistas para crear el contenido de cada actividad. Además, también hemos visto que tenemos dos tipos de vistas: diseños para subdividir la [&#8230;]]]></description>
										<content:encoded><![CDATA[<p style="text-align:justify;" align="justify">En posts anteriores vimos de qué elementos disponemos en Android para diseñar las interfaces de usuario de nuestras aplicaciones. Por un lado tenemos <a href="https://columna80.wordpress.com/2011/07/29/introduccin-a-las-actividades-de-android/">actividades</a> para crear cada una de las diferentes pantallas, y vistas para crear el contenido de cada actividad. Además, también hemos visto que tenemos <a href="https://columna80.wordpress.com/2011/09/12/las-vistas-android-diseos-y-widgets/">dos tipos de vistas</a>: diseños para subdividir la actividad y situar el resto de vistas, y widgets para mostrar información al usuario y permitirle interactuar con la aplicación.</p>
<p style="text-align:justify;" align="justify">En este post vamos a ver cómo se crean todos estos elementos y qué propiedades tienen en común. Más adelante veremos cómo, una vez creados, los incluimos y mostramos en nuestras actividades.</p>
<p style="text-align:justify;" align="justify">Podemos crear widgets y diseños tanto por código como utilizando archivos de recursos en XML situados en la carpeta <code>layouts</code>. Ni qué decir tiene que es preferible optar por la segunda opción, que no sólo permite tener una vista previa aproximada de la interfaz en tiempo de codificación, sino también disponer de diferentes interfaces de usuario para una misma actividad. Esto permite escoger la más adecuada en tiempo de ejecución en función del tamaño de la pantalla o del idioma que tenga configurado el dispositivo, por ejemplo.</p>
<p style="text-align:justify;" align="justify">Aunque me centraré en los recursos XML, también iré mencionando los elementos Java que se corresponden con ellos. En <a title="Diseñando interfaces en Android: codificación" href="https://columna80.wordpress.com/2011/10/09/diseando-interfaces-en-android-codificacin/">este otro post</a> explico cómo se crean interfaces de usuario completas por código.</p>
<p><span id="more-625"></span></p>
<h3 align="justify">Diseño en XML</h3>
<p style="text-align:justify;" align="justify">Para empezar, veamos un pequeño ejemplo de interfaz de usuario creada en XML:</p>
<pre class="brush: xml; auto-links: false; gutter: false; pad-line-numbers: true; title: ; wrap-lines: false; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:id=&quot;@+id/principal&quot;
    android:layout_width=&quot;fill_parent&quot;
    android:layout_height=&quot;fill_parent&quot;
    android:orientation=&quot;vertical&quot;&gt;
    &lt;TextView
        android:id=&quot;@+id/etiqueta1&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Esto es una etiqueta de texto&quot;&gt;
    &lt;/TextView&gt;
    &lt;Button
        android:id=&quot;@+id/boton1&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Esto es un botón&quot;&gt;
    &lt;/Button&gt;
&lt;/LinearLayout&gt;
</pre>
<p style="text-align:justify;" align="justify">Se trata de un diseño <strong>LinearLayout</strong> vertical que ocupa todo el área disponible de la actividad y que contiene dos widgets: una etiqueta de texto y un botón. Este diseño genera la interfaz de usuario que se muestra en las siguientes capturas. Hay que tener en cuenta que el aspecto de los widgets depende la versión de Android que utilicemos, por lo que variará de un dispositivo a otro o de un emulador a otro. La captura de la izquierda está hecha con Android 1.5 y la de la derecha con la versión 2.3:</p>
<p align="center"><a href="https://columna80.wordpress.com/wp-content/uploads/2011/09/0028-01-interfaz-de-usuario-en-android-1-5.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:5px;" title="Interfaz de usuario en Android 1.5" src="https://columna80.wordpress.com/wp-content/uploads/2011/09/0028-01-interfaz-de-usuario-en-android-1-5_thumb.png?w=164&#038;h=244" alt="Interfaz de usuario en Android 1.5" width="164" height="244" border="0" /></a><a href="https://columna80.wordpress.com/wp-content/uploads/2011/09/0028-02-interfaz-de-usuario-en-android-2-3.png" target="_blank"><img loading="lazy" style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:5px;" title="Interfaz de usuario en Android 2.3" src="https://columna80.wordpress.com/wp-content/uploads/2011/09/0028-02-interfaz-de-usuario-en-android-2-3_thumb.png?w=164&#038;h=244" alt="Interfaz de usuario en Android 2.3" width="164" height="244" border="0" /></a></p>
<p style="text-align:justify;" align="justify">La estructura del archivo XML es de tipo árbol, con un elemento principal que hace de raíz y una serie de elementos que se incluyen unos dentro de otros a diferentes niveles de profundidad. Lo más importante aquí es que sólo tenemos un elemento raíz del que dependerán, directa o indirectamente, el resto de vistas. Lo habitual es que ese elemento sea un diseño que define la organización principal de la actividad y que contiene el resto de diseños y widgets. No obstante, también podría ser un widget, si es lo único que necesita la actividad.</p>
<p style="text-align:justify;" align="justify">En el ejemplo, la raíz es un <strong>LinearLayout</strong> vertical, definido con la etiqueta XML <strong>&lt;LinearLayout&gt;</strong>. Por comodidad, la mayoría de etiquetas y atributos de los archivos XML se llaman de forma idéntica a las clases y propiedades con que se corresponden (aunque hay excepciones). Dentro de la etiqueta <strong>&lt;LinearLayout&gt;</strong> se incluyen otras dos, <strong>&lt;TextView&gt;</strong> y <strong>&lt;Button&gt;</strong>, que se corresponden con los widgets del mismo nombre (la etiqueta de texto y el botón que se muestran en las capturas).</p>
<blockquote>
<p align="justify"><strong>Una pequeña aclaración</strong></p>
<p style="text-align:justify;" align="justify"><em>En Android se utiliza el término diseño (</em>layout)<em> para referirse tanto a la vista que contiene otras vistas y se encarga de organizarlas y dimensionarlas, como al conjunto de vistas (incluyendo widgets y diseños) que se muestran en una actividad. Por este motivo la carpeta en la que se incluyen los archivos XML como el de arriba se llama también </em><code>layout</code><em>.<br />
En este blog utilizaré el término diseño para referirme a ambas cosas indistintamente. Espero que el contexto deje claro de qué estoy hablando en cada momento.</em></p>
</blockquote>
<h3 align="justify">Propiedades de las vistas</h3>
<p style="text-align:justify;" align="justify">El aspecto y el comportamiento de las vistas, tanto diseños como widgets, se pueden personalizar mediante propiedades. En el archivo XML las propiedades se representan mediante atributos de las etiquetas que se corresponden con las vistas. En la API, las propiedades son atributos privados o protegidos de las clases que implementan las vistas.</p>
<p style="text-align:justify;" align="justify">Para modificar una propiedad sólo tenemos que darle un valor al atributo correspondiente, incluyéndolo dentro de la etiqueta XML que representa la vista. Sin embargo, por código no podemos hacer lo mismo, dado que los atributos privados o protegidos no son accesibles y el lenguaje java no permite definir propiedades en las clases como hacen otros lenguajes (C#, por ejemplo). Por este motivo, cada atributo XML se suele corresponder con un método de la clase cuyo nombre coincide (casi siempre) con el del atributo, pero con la cadena <strong>set</strong> como prefijo. Este prefijo es una convención habitual para indicar que el método sirve para establecer el valor de un atributo de la clase. Si la clase permite también recuperar el valor del atributo, existirá un método similar con prefijo <strong>get</strong>.</p>
<p style="text-align:justify;" align="justify">Hay que tener en cuenta, que cuando hablo del nombre del atributo me refiero a lo que va a continuación de <strong>android:</strong>. Este prefijo que llevan todos los atributos del archivo XML es el espacio de nombres en el que se definen. Sin entrar en muchos detalles (no es el objetivo de este post) los espacios de nombres en XML tienen una función similar a la de los paquetes en Java (salvando las distancias): permiten definir símbolos dentro de un ámbito de forma que no tengan conflictos, por tener el mismo nombre, con los de otro ámbito. Los espacios de nombres se definen en esquemas XML que incluyen las etiquetas disponibles, los atributos que puede tener cada etiqueta y qué etiquetas pueden estar contenidas dentro de otras. En nuestro archivo XML, anteponer el prefijo <strong>android:</strong> sirve para especificar el espacio de nombres donde se declara el atributo. El espacio de nombres está declarado en el atributo <strong>xmlns</strong> de la etiqueta <strong>&lt;LinearLayout&gt;</strong> y aunque pueda parecer una URL (dirección web) en realidad sólo es un identificador con forma de URL.</p>
<p style="text-align:justify;" align="justify">La API de Android aprovecha la herencia de java para homogeneizar las propiedades disponibles para las vistas. Dado que las propiedades son atributos de clases, pueden ser heredadas por las clases hijas (si se definen como protegidas y no como privadas). De esta forma, como todas las vistas heredan directa o indirectamente de la clase <strong>View</strong>, las propiedades que se definen en esta clase estarán disponibles en todas las hijas.</p>
<h4 align="justify"><a name="identificadores"></a>Identificadores</h4>
<p style="text-align:justify;" align="justify">Una de las propiedades que proporciona la clase <strong>View</strong> es la que se utiliza en el ejemplo como <strong>android:id</strong>. Se trata de un identificador para las vistas, aunque no es obligatorio. En el archivo XML, asignar un identificador a una vista sirve para poder hacer referencia a ella tanto en el propio archivo XML como en la actividad que lo utilice. Si no vamos a referenciar una vista no es necesario asignarle un identificador.</p>
<p style="text-align:justify;" align="justify">Para poder usar el identificador XML desde el código Java, el compilador genera una clase llamada <strong>R</strong> en la que se incluye una constante por cada atributo <strong>Id</strong> del archivo XML. El método <strong>findViewById</strong> de la clase <strong>Activity</strong> nos permite obtener la vista que necesitamos a partir de estas constantes de la clase <strong>R</strong>.</p>
<p style="text-align:justify;" align="justify">Por otro lado, cuando la interfaz de usuario se crea por entero desde el código tenemos objetos definidos para cada vista y podemos usarlos para acceder a sus propiedades o como referencia en otras vistas, sin necesidad de asignar identificadores.</p>
<p style="text-align:justify;" align="justify">Aunque a primera vista no lo parece, el identificador es en realidad un número. De hecho, el método <strong>setId</strong> que permite establecer el identificador por código recibe un entero (<strong>int</strong>) como parámetro. Sin embargo, trabajar directamente con identificadores numéricos en los archivos XML no resulta demasiado práctico, por lo que el compilador nos permite utilizar unas cadenas de texto especiales que luego son traducidas a los números que correspondan. El formato de esas cadenas de texto es el siguiente:</p>
<pre>   @[&lt;nombre_de_paquete&gt;:|+]&lt;tipo_de_recurso&gt;/&lt;nombre_de_recurso&gt;</pre>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;">El símbolo @ del comienzo le indica al procesador del archivo XML que va a ser necesario expandir la cadena que viene a continuación reemplazándola por el valor correspondiente.</p>
</li>
<li>
<p style="text-align:justify;">El siguiente campo, opcional, puede ser un nombre de paquete o el símbolo +. El símbolo + indica que el recurso al que se hace referencia no existe y tiene que crearlo el compilador. Sólo se utiliza para identificadores. De esta forma, el compilador asigna un valor numérico único a cada identificador. El nombre de paquete se utiliza cuando se quiere hacer referencia a un recurso que ha sido creado en otra parte.</p>
</li>
<li>
<p style="text-align:justify;">Los dos siguientes campos son obligatorios: el tipo de recurso y su nombre. En nuestro caso el tipo de recurso es <code><strong>id</strong></code>, pero este formato también sirve para hacer referencia a otros recursos, cada uno de los cuales tiene un tipo concreto. Por su parte, el nombre del recurso es el identificador que vamos a usar para la vista dentro del archivo XML. Por lo tanto, no deberíamos asignar el mismo nombre a diferentes vistas.</p>
</li>
</ul>
</div>
<blockquote>
<p align="justify"><strong>Nota</strong></p>
<p style="text-align:justify;" align="justify"><em>Aunque el compilador no va a protestar si usamos el mismo nombre en más de una vista, sólo se va a crear un identificador y, por tanto, una única constante en la clase <strong>R</strong>. Si tratamos de localizar la vista que le corresponde, se devolverá siempre la primera que se encuentre con el identificador buscado, lo que puede dar lugar a comportamientos no deseados. Incluso, si el tipo de la vista que se devuelve no se corresponde con el del objeto al que se intenta asignar, se producirá un error en la aplicación durante su ejecución.</em></p>
</blockquote>
<p style="text-align:justify;" align="justify">En resumen, si asignamos a un atributo <strong>Id</strong> una cadena como <code>@+id/principal</code>, el compilador le asignará un número a la vista, por ejemplo el 0x7f050000 (2.131.034.112 en hexadecimal), y creará una constante de nombre <strong>R.layout.principal</strong> en el archivo <code>R.java</code>. La constante será de tipo <strong>int</strong> y tendrá el valor 0x7f050000. Además, cuando se cree el objeto correspondiente a la vista, se le asignará el número 0x7f050000 como identificador (usando <strong>setId</strong>).</p>
<p style="text-align:justify;" align="justify">Si más adelante usamos una cadena como <code>@id/principal</code> en otro atributo, el compilador reconocerá el nombre del recurso y lo remplazará por el mismo valor numérico, 0x7f050000, para pasárselo al método que se corresponda con el atributo.</p>
<h4 align="justify">Otras propiedades</h4>
<p style="text-align:justify;" align="justify">La clase <strong>View</strong> proporciona otras muchas propiedades a las vistas. Veamos algunas de las más habituales:</p>
<div align="justify">
<ul>
<li>
<p style="text-align:justify;"><strong>android:background</strong> (<strong>setBackgroundResource</strong>, <strong>setBackgroundDrawable</strong>, <strong>setBackgroundColor</strong>): permite reemplazar el fondo predeterminado de la vista por un color uniforme o una imagen.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:clickable</strong> (<strong>setClickable</strong>): determina si la vista responderá a pulsaciones sobre ella o no. Se puede hacer que cualquier vista responda a pulsaciones aunque no sea su cometido habitual.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:minWidth</strong> (<strong>setMinimumHeight</strong>) y <strong>android:minHeight</strong> (<strong>setMaximumHeight</strong>): permiten especificar un tamaño mínimo (ancho y alto) para la vista. Como los tamaños de pantalla de los dispositivos Android son muy variados y los diseños tienden a adaptarse a ellos, no se suelen fijar los tamaños de las vistas. Pero sí se puede establecer un mínimo que garantice la correcta presentación de su contenido.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:padding</strong> (<strong>setPadding</strong>): el padding es un espacio alrededor de los límites de la vista, pero dentro de ella, que el contenido no puede ocupar. El padding sirve para alejar el contenido de los bordes de la vista, evitando que quede demasiado cerca o pegado a los contenidos de las vistas circundantes. Además del atributo <strong>android:padding</strong>, que permite definir el padding para los cuatro bordes de la vista simultáneamente, hay atributos particulares para cada borde: <strong>paddingLeft</strong>, <strong>paddingRight</strong>, <strong>paddingTop</strong> y <strong>paddingBottom</strong>. En <a title="Diseñando interfaces en Android: padding y margen" href="https://columna80.wordpress.com/2011/09/25/diseando-interfaces-en-android-padding-y-margen/">este post</a> explico con más detalle el padding y sus diferencias con el margen.</p>
</li>
<li>
<p style="text-align:justify;"><strong>android:visibility</strong> (<strong>setVisibility</strong>): permite controlar la visibilidad de la vista. Tiene tres posibles valores:</p>
<ul>
<li>
<p style="text-align:justify;"><code><strong>visible</strong></code>: la vista se muestra en la actividad. Es el estado predeterminado.</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>invisible</strong></code>: la vista no se muestra en la actividad, pero el diseño la tiene en cuenta. El resultado es que se deja sin ocupar el espacio que ocuparía si fuera visible.</p>
</li>
<li>
<p style="text-align:justify;"><code><strong>gone</strong></code>: la vista ni se muestra ni la tiene en cuenta el diseño. Es como si no se hubiera incluido nunca en la actividad. Sin embargo, la vista existe y sus propiedades son accesibles.</p>
</li>
</ul>
</li>
</ul>
</div>
<p style="text-align:justify;" align="justify">Luego, cada vista concreta añade sus propias propiedades. Por ejemplo, <strong>&lt;TextView&gt;</strong> y <strong>&lt;Button&gt;</strong> disponen de un atributo <strong>android:text</strong>, que permite establecer el texto que mostrarán. En futuros posts iremos viendo las propiedades particulares de diferentes diseños y widgets.</p>
<p class="sticky" style="text-align:center;" align="center">Recuerda que en <a href="https://columna80.wordpress.com/android/" target="_blank">esta página</a> dispones de enlaces a todos los artículos sobre Android que he publicado en <strong>La columna 80</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://columna80.wordpress.com/2011/09/17/diseando-interfaces-en-android-xml-y-propiedades/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">625</post-id>
		<media:content url="https://2.gravatar.com/avatar/b273e833989b39bb3b2bdc53ec5321208be34b7c7fa603e62163cc47fdd6c186?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">ajvico</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/09/0028-01-interfaz-de-usuario-en-android-1-5_thumb.png" medium="image">
			<media:title type="html">Interfaz de usuario en Android 1.5</media:title>
		</media:content>

		<media:content url="https://columna80.wordpress.com/wp-content/uploads/2011/09/0028-02-interfaz-de-usuario-en-android-2-3_thumb.png" medium="image">
			<media:title type="html">Interfaz de usuario en Android 2.3</media:title>
		</media:content>
	</item>
	</channel>
</rss>
