Fundamentos de Android: Editor gráfico de diseño

Fundamentos de Android: Editor gráfico de diseño

En esta entrada vamos a practicar con el editor gráfico de diseño de Android Studio. Para ello vamos a crear una aplicación con una actividad del tipo "Acerca de" (About) que mostrará información utilizando distintos elementos visuales (views), como un TextView, una ImageView y un ScrollView, cuyo diseño se organizarán en un LinearLayout.

Como siempre, empezamos creando un nuevo proyecto en Android Studio. En este caso partimos de una Actividad vacía (Empty Activity):



Como ya sabemos, Android Studio generará diversos archivos para este nuevo proyecto, entre ellos MainActivity.kt y layout/activity_main.xml que contienen, respectivamente, una actividad vacía y un diseño con un ConstraintLayout como grupo raíz de elementos visuales, el cual contiene un TextView con el texto "Hello World".

Ahora abrimos el archivo de la actividad MainActivity.kt y buscamos al final de la función onCreate el código setContentView(R.layout.activity_main). Esta función (setContentView) conecta la actividad con el archivo de diseño especificado como argumento (ya sabemos que R es una clase generada automáticamente con referencias a todos los recursos, y en este caso apunta a layout/activity_main.xml).

Lo primero que vamos a hacer es cambiar el grupo raíz generado (ConstraintLayout). Para ello, en el archivo activity_main.xml, en modo Text, sustituimos el ConstraintLayout por un LinearLayout con orientación vertical, y también eliminamos el TextView, quedando el archivo así:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

</LinearLayout>

En el mismo archivo, ahora nos movemos a la vista gráfica Design (ten en cuenta que las vistas Text y Design muestran el mismo diseño solo que de una manera diferente, por lo que los cambios realizados en una vista se reflejan automáticamente en la otra):



En el Editor Gráfico (Layout Editor) podemos distinguir 5 zonas principales:
  1. Editor de diseño (Design editor): en la parte central del editor gráfico, muestra una representación visual del diseño de la pantalla.
  2. Barra de herramientas (Toolbar): panel sobre el editor de diseño que proporciona botones para configurar la apariencia y cambiar algunos atributos de la visualización del diseño.
  3. Paleta (Palette): en la parte superior izquierda, proporciona una lista de elementos (views) y grupos de elementos que se pueden arrastrar al diseño o al panel de componentes.
  4. Árbol de componentes (Component Tree): panel bajo la paleta que muestra la jerarquía de diseño como un árbol de elementos. Este panel de componentes es especialmente útil cuando hay elementos pequeños, ocultos o superpuestos que resulta difícil seleccionar en el editor de diseño.
  5. Atributos (Attributes): panel en la parte derecha que muestra los atributos para el elemento visual o el grupo de elementos seleccionado actualmente. Con el icono superior de las flechas horizontales podemos alternar entre una lista completa de atributos y una selección de atributos. Para incluir un atributo en esta selección de favoritos, desplegamos la lista completa de atributos, deslizamos el ratón sobre el margen izquierdo de los atributos y veremos una estrella, hacemos clic sobre la estrella del atributo que nos interesa y ya está disponible en la vista de selección de atributos (y con el proceso inverso lo retiramos de la lista de atributos favoritos).

Ahora desde el panel de la paleta de elementos, vamos a seleccionar un TextView (disponible en Common y en Text) y lo arrastramos hasta el editor de diseño (observa que el nuevo elemento aparece también en el panel del árbol de componentes como un elemento secundario del grupo raíz, que es el LinearLayout):



También observamos que al seleccionar el nuevo TextView aparecen ciertos valores por defecto en el panel derecho de atributos. Podemos personalizarlos de esta manera:
  • ID: id_texto1
  • text (el campo sin el icono de una llave): Kotlin Doc
  • textAppearance (desplegamos para ver más atributos) > textSize: 20sp
  • textAppearance > textColor (con Ctrl+Space muestra un desplegable con opciones): @android:color/black
  • textAppearance > textAlignment: Center

En el árbol de componentes, podemos ver un icono de advertencia junto al TextView. Al pasar el ratón sobre él aparece una ventana emergente que explica el aviso, y si pulsamos sobre el icono nos muestra un mensaje que explica el posible error. Para solucionarlo, desde el campo text de atributos, pulsamos sobre el botón de la derecha con tres puntos:



Se abre la ventana Resources, y arriba a la derecha seleccionamos Add new resource > New string Value. En el campo Resource name escribimos 'nombre' y en Resource value el texto del elemento (Kotlin Doc):



Observa que en el panel del árbol de componentes ha desaparecido la advertencia y que en el panel de atributos, en el campo text, ahora aparece '@string/nombre' como una referencia al valor que se almacena en el archivo values/strings.xml. Si abres este archivo verás el recurso de texto recién creado:
<resources>
    <string name="app_name">About</string>
    <string name="nombre">Kotlin Doc</string>
</resources>

También podemos agregar recursos en res/values desde la vista Text de activity_main.xml: en la etiqueta textSize del TextView, hacemos clic sobre su valor (20sp) y pinchamos sobre el icono de la bombilla (o bien utilizamos el atajo Alt+Intro) y seleccionamos Extract dimension resource y le asignamos un nombre, por ejemplo text_size, y mantenemos el valor de 20sp (esto mismo lo podemos hacer en la vista Design como hicimos antes). Este nuevo recurso esta ahora almacenado en values/dimens.xml, y se hace referencia a él con android:textSize="@dimen/text_size".

Ahora vamos a agregar estilo al TextView. Vemos que el texto aparece en la parte superior de la pantalla, por lo que necesitamos agregarle un espacio (padding) y un margen. El padding es el espacio que existe, dentro de los límites del elemento, entre sus bordes y su contenido:



El tamaño de un elemento visual (view) incluye su padding. Los atributos comúnmente aplicados para ajustar el espacio de padding son android:padding, android:paddingTop, android:paddingBottom, android:paddingStart, android:paddingEnd, android:paddingLeft y android:paddingRight.

Por su parte, el margen (margin) es el espacio que hay fuera de los bordes del elemento, esto es, el espacio desde el límite del elemento hasta su contenedor (elemento padre). Podemos ajustarlo con estos atributos: android:layout_margin, android:layout_marginBottom, android:layout_marginStart, android:layout_marginEnd, android:layout_marginLeft y android:layout_marginRight.

Nota de compatibilidad: Para maximizar la compatibilidad de la aplicación con lenguajes que fluyen de izquierda a derecha y de derecha a izquierda, tanto para el padding como para el margen, si tu aplicación apunta a nivel de API 17 (Android 4.2) o superior se deben utilizar los atributos Start y End en lugar de Left y Right (por ejemplo, android:layout_marginLeft debería convertirse en android:layout_marginStart), pero si quieres que tu aplicación funcione con versiones previas a Android 4.2 (si targetSdkVersion o minSdkVersion es 16 o inferior) debes utilizar los atributos Start y End además de Left y Right.

Para añadir un padding a nuestra aplicación, en la vista gráfica (Design), seleccionamos el TextView ya sea desde el árbol de componentes o desde el editor de diseño, y en el panel de atributos pulsamos para ver todos los atributos; pulsamos sobre el icono de la lupa para buscar Padding, en los resultados desplegamos Padding y en top pulsamos sobre los tres puntos para abrir la ventana de Resources: Add new resource > New dimen Value. Le asignamos un nombre (small_padding) y un valor (8dp), donde dp (density-independent) es una unidad de medida que se utiliza para que un elemento de la interfaz de usuario se vea del mismo tamaño en pantallas con diferentes densidades (sin embargo para el tamaño del texto es mejor utilizar siempre sp: píxeles escalables).



Para separar el TextView del elemento principal (LinearLayout) podemos agregarle un margen superior para desplazarlo hacia abajo. Con el TextView selecionado, en el panel de Atributos buscamos 'margin', desplegamos Layout_Margin y en top creamos un nuevo recurso de nombre layout_margin y valor 16dp.



En el archivo values/dimens.xml podemos comprobar estos cambios:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="text_size">20sp</dimen>
    <dimen name="small_padding">8dp</dimen>
    <dimen name="layout_margin">16dp</dimen>
</resources>

Ahora podemos cambiar la fuente al texto del TextView. Para ello, con el TextView seleccionado, en el panel de atributos buscamos 'fontFamily', y en el campo fontFamily hacemos clic en mitad del campo para visualizar la lista de fuentes, y al final de esta lista pulsamos sobre More Fonts para abrir la ventana de Recursos. En el campo de búsqueda escribimos rob y selecionamos Fonts: Roboto, Preview: Regular y 'Add font to project':



La fuente Roboto forma parte de la biblioteca de soporte y la hemos agregado como un recurso: ahora el atributo fontFamily del TextView tiene el valor @font/roboto y la carpeta res tiene la carpeta font que contiene el archivo de fuentes roboto.ttf.

Además de utilizar atributos de forma independiente como hasta ahora, también podemos utilizar estilos. Un estilo es una colección de atributos que especifican valores de apariencia y formato de un elemento visual (view), incluyendo atributos como color y tamaño de la fuente, color de fondo (background), padding, margen...

Podemos conseguir el formato de un elemento y reutilizarlo en otros elementos de la aplicación, lo que da a la aplicación una apariencia consistente. Por ejemplo, para extraer el estilo que hemos aplicado al TextView, lo seleccionamos en el panel del árbol de componentes, y con el botón secundario del ratón seleccionamos Refactor > Extract Style. En el cuadro de diálogo Extract Android Style desactivamos las casillas layout_width, layout_height y textAlignment para que estos atributos no formen parte del estilo puesto que suelen tener valores diferentes para otros elementos, y le asignamos un nombre al estilo, por ejemplo AppEstilo:



Un estilo también es un recurso, por lo que el estilo se guarda en el archivo values/styles.xml:
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    <style name="AppEstilo">
        <item name="android:textSize">@dimen/text_size</item>
        <item name="android:textColor">@android:color/black</item>
        <item name="android:paddingTop">@dimen/small_padding</item>
        <item name="android:layout_marginTop">@dimen/layout_margin</item>
        <item name="android:fontFamily">@font/roboto</item>
    </style>

</resources>

En activity_main.xml, con el TextView seleccionado, en el panel de atributos también vemos que el atributo style tiene el valor de @style/AppEstilo.

Ahora a nuestra aplicación le vamos a añadir una imagen utilizando una ImageView desde el editor de diseño. Para ello, en la paleta de elementos seleccionamos y arrastramos una ImageView y la soltamos en el árbol de componentes, bajo el TextView. Al hacer esto se abre la ventana de recursos: seleccionamos Drawable, expandimos android y seleccionamos btn_star_big_on (estrella amarilla):



En el editor de diseño podemos ver algo así (la imagen de la estrella aparece bajo el texto puesto que el LinearLayout tiene una orientación vertical, lo que hace que los elementos se organicen uno bajo otro):



Cambiando a la vista de texto (Text) podemos observar el código generado para la ImageView:
<ImageView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:srcCompat="@android:drawable/btn_star_big_on" />

Para reasignar un nombre al atributo ID de la ImageView, hacemos clic con el botón secundario sobre "@+id/imageView" y seleccionamos Refactor -> Rename. En el cuadro de diálogo, donde pone @+id/imageView lo cambiamos por otro nombre manteniendo el prefijo @+id, por ejemplo @+id/estrella. Nota: aunque se puede cambiar el nombre directamente, es buena práctica hacerlo de esta manera puesto que así se renombra en todas sus apariciones del proyecto.

Si volvemos a la vista de diseño (Design), en el árbol de componentes, junto a la imagen aparece un icono de advertencia que nos avisa que falta una descripción del contenido de la imagen (algunos lectores de pantalla utilizan esta descripción para describir la imagen al usuario). Para añadirla, con la ImageView seleccionada, en el panel de atributos buscamos contentDescription y abrimos la ventana de recursos con el botón de tres puntos. Seleccionamos Add new resource > New string Value y asignamos un nombre (estrella_amarilla) y un valor (Estrella amarilla). La advertencia ha desaparecido.

Para separar la imagen del texto, en el panel de atributos le agregamos un margen superior de 16dp a la imagen. Recuerda que en values/dimens.xml ya tenemos este valor con el nombre layout_margin, por lo que lo podemos aplicar desde el atributo Layout_Margin -> top -> Resources -> (Project) layout_margin. Ahora la imagen de la estrella se ha desplazado ligeramente hacia abajo.

Ahora vamos a añadir un ScrollView, que es un grupo que permite desplazar los elementos que contiene. Esto permite al usuario desplazar sobre la pantalla el elemento que no es completamente visible para alcanzar las partes no visibles inicialmente. Aunque habitualmente un ScrollView contiene primero un LinearLayout y dentro de él se agregan otros elementos, cuando el ScrollView solo contiene un elemento (como en nuestro caso) podemos prescindir del LinearLayout intermedio.

Desde la vista de diseño (Design), en la paleta de elementos seleccionamos y arrastramos un ScrollView al ábol de componentes bajo la imagen de la estrella. En la vista Text podemos comprobar el código generado, algo así:
<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />
</ScrollView>

Vemos que la anchura y la altura del ScrollView coinciden con el elemento principal o padre, por lo que después del espacio utilizado por el TextView y la ImageView, el ScrollView ocupa el espacio restante disponible en la pantalla. Al agregar una identificación con el atributo ID (android:id="@+id/scroll"), le estamos dando al sistema Android un controlador que permite que cuando el usuario gira el dispositivo, el sistema conserva la posición del desplazamiento.

Dentro del ScrollView eliminamos el LinearLayout generado. Volvemos a la vista de diseño y desde la paleta de elementos arrastramos un TextView al árbol de componentes bajo el scroll, como elemento secundario suyo.

Desde el panel de atributos, asignamos un valor al id del nuevo TextView, por ejemplo about_text. Y en el atributo style abrimos la ventana de recursos y le aplicamos el estilo que guardamos antes para nuestra aplicación con el nombre AppEstilo.



Ahora le vamos a añadir un contenido al TextView. Para ello, abrimos values/strings.xml y creamos un nuevo recurso llamado texto_about y le asignamos como valor un texto largo, por ejemplo (utilizamos \n para indicar un salto de línea, <b> para negrita y <i> para cursiva):
<string name="texto_about"><b>Kotlin Doc</b>
    \n\nKotlin Doc comparte y divulga en español información y ejemplos sobre programación con Kotlin y Android.
    \n\nEl contenido de este sitio se ofrece abiertamente (CC Attribution 4.0 International) y eres libre para compartirlo —copiar y redistribuir el material en cualquier medio o formato— y adaptarlo —remezclar, transformar y crear a partir del material original— para cualquier finalidad siempre que reconozcas adecuadamente la autoría con, al menos, un enlace a este sitio.
    \n\nLa información que aquí se presenta se comparte libremente bajo las condiciones de la licencia CC BY 4.0 con la esperanza de que sea útil, pero SIN NINGUNA GARANTÍA.
    \n\nKotlin Doc is licensed under CC BY 4.0.
    \n\nKotlin Doc is not associated with <i>JetBrains</i> or with the <i>Kotlin Foundation</i>.
    \nThe Kotlin trademark and associated marks, logos and domain names belong to the Kotlin Foundation.</string>

Ahora en el atributo text del TextView asignamos el valor el recurso de texto que acabamos de crear.

Para facilitar la lectura, le agregamos un espacio entre líneas asignando al atributo lineSpacingMultiplier un valor de 1.2. Además al elemento padre LinearLayout, en el atributo Padding (start y end) le asignamos el valor 16dp que tenemos guardado en values/dimens.xml con el nombre de layout_margin (o podemos crear un nuevo recurso llamado layout_padding con ese mismo valor):



Si al desplazar el texto hasta el final no se puede leer completamente la última línea, lo puedes solucionar añadiendo también un espacio al TextView, asignando al atributo Padding -> bottom el valor de layout_margin.

Ejecuta la aplicación y comprueba que puedes desplazar verticalmente el texto por la ventana para leer todo su contenido.

Comentarios

Entradas populares

I/O: entrada y salida de datos en consola

Recursos gratis para aprender Kotlin

Lectura y escritura de archivos