Cómo crear diseños XML para Android

1. Antes de comenzar

En este codelab, compilarás el diseño para una app básica de calculadora de propinas. Al final del codelab, tendrás una IU en funcionamiento para la app, pero esta aún no calculará la propina. En los próximos codelabs, nos ocuparemos de que la app funcione y tenga un aspecto más profesional.

Requisitos previos

  • Poder crear y ejecutar una app para Android a partir de una plantilla en Android Studio

Qué aprenderás

  • Cómo leer y escribir diseños XML en Android
  • Cómo compilar el diseño de un formato sencillo de modo que reciba las entradas de texto del usuario y sus elecciones

Qué compilarás

  • La IU de una app para Android que calcula propinas

Requisitos

2. Inicia el proyecto

Consulta la calculadora de propinas en Google: https://www.google.com/search?q=tip+calculator

18da3c120daa0759.png

En esta ruta de aprendizaje, compilarás una versión simple de una calculadora de propinas como una app para Android.

Los desarrolladores suelen trabajar de esta manera: obtienen una versión simple de la app lista y en funcionamiento parcial (incluso si no tiene muy buen aspecto) y, luego, la mejoran para que funcione por completo y resulte visualmente elegante.

Al final de este codelab, tu app de calculadora de propinas se verá de la siguiente manera:

bcc5260318477c14.png

Utilizarás estos elementos de la IU que proporciona Android:

  • EditText: Se usa para ingresar y editar texto.
  • TextView: Este elemento se usa para mostrar texto, como la pregunta sobre el servicio y el monto de la propina.
  • RadioButton: Es un botón de selección para elegir cada opción de propina.
  • RadioGroup: Se usa a efectos de agrupar las opciones del botón de selección.
  • Switch: Se trata de un botón de activación/desactivación para elegir si se redondea la propina o no.

Cómo crear un proyecto de actividad vacía

  1. Para comenzar, crea un nuevo proyecto de Kotlin en Android Studio con la plantilla Empty Activity.
  2. Usa el nombre "Tip Time" para la app, que debe tener un nivel de API 19 (KitKat) como mínimo. El nombre del paquete es com.example.tiptime.

4f7619e9faff20e9.png

  1. Haz clic en Finish para crear la app.

3. Lee y comprende XML

En lugar de usar el editor de diseño que ya conoces, modificarás el XML que describe la IU para compilar el diseño de tu aplicación. Obtener información para entender y modificar diseños de la IU mediante XML resulta importante para ti como desarrollador de Android.

Mirarás y editarás el archivo en formato XML que define el diseño de la IU de esta app. XML significa lenguaje de marcación extensible, que es una forma de describir los datos mediante un documento basado en texto. Debido a que el formato XML es extensible y muy flexible, se utiliza para varias cosas diferentes, incluida la definición del diseño de la IU de las apps para Android. Quizá recuerdes de codelabs anteriores que otros recursos usados en tu app, como las strings, también se definen en un archivo en formato XML llamado strings.xml.

La IU de una app para Android se compila como una jerarquía de contención de componentes (widgets) y de los diseños en pantalla de esos componentes. Ten en cuenta que estos diseños son componentes de la IU en sí mismos.

Serás tú quien describa la jerarquía de vistas de los elementos de la IU en la pantalla. Por ejemplo, un ConstraintLayout (el elemento superior) puede contener Buttons, TextViews, ImageViews u otras vistas (los elementos secundarios). Recuerda que ConstraintLayout es una subclase de ViewGroup. Te permitirá posicionar o dimensionar las vistas secundarias de manera flexible.

74c7c563d18fffd4.png

Jerarquía de contención de una app para Android

32df120272b2331d.png

Cada elemento de la IU está representado por un elemento XML en el archivo en formato XML. Cada elemento comienza y termina con una etiqueta, y cada etiqueta comienza con un < y termina con un >. Así como puedes establecer atributos sobre los elementos de la IU mediante el editor de diseño (vista de diseño), los elementos XML también pueden tener atributos. Simplificado, el XML de los elementos de la IU mencionados arriba podría ser algo así:

<ConstraintLayout>
    <TextView
        text="Hello World!">
    </TextView>
</ConstraintLayout>

8dea708333aebabe.png

Veamos un ejemplo real.

  1. Abre activity_main.xml (res > layout > activity_main.xml).
  2. Notarás que la app muestra una TextView que dice "Hello World!" dentro de un ConstraintLayout, como viste en proyectos anteriores creados a partir de esta plantilla.

4fbdb64c02d62e73.png

  1. Encuentra las opciones para las vistas Code, Split y Design en la parte superior derecha del editor de diseño.
  2. Selecciona la vista Code.

6203bec920791bcc.png

Así se ve el XML en activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Ocurre mucho más que lo que vemos en el ejemplo simplificado, pero Android Studio hace algunas cosas a fin de ayudar a que el XML sea más fácil de leer, tal como lo hace con tu código Kotlin.

  1. Observa la sangría. Android Studio hace esto automáticamente para mostrarte la jerarquía de elementos. La TextView tiene sangría porque está contenida en el ConstraintLayout. El ConstraintLayout es el elemento superior, y la TextView es el secundario. Los atributos de cada elemento se muestran con una sangría a efectos de indicar que forman parte de ese elemento.
  2. Observa la codificación por color: algunas cosas están en azul, otras están en verde, etc. Las partes similares del archivo se dibujan con el mismo color para ayudarte a ver las correspondencias. En particular, observa que Android Studio dibuja el principio y el final de las etiquetas de elementos con el mismo color (nota: Es posible que los colores que se usan en el codelab no coincidan con lo que ves en Android Studio).

Etiquetas, elementos y atributos XML

A continuación, se muestra una versión simplificada del elemento TextView de modo que puedas ver algunas de sus partes importantes:

<TextView
    android:text="Hello World!"
/>

La línea con <TextView es el inicio de la etiqueta y la línea con /> es el final de ella. La línea con android:text="Hello World!" es un atributo de la etiqueta. Representa el texto que mostrará la TextView. Estas 3 líneas son una abreviatura de uso frecuente denominada etiqueta de elemento vacío. Sería lo mismo si lo escribieras con una etiqueta de inicio y una etiqueta de fin separadas, como se muestra a continuación:

<TextView
    android:text="Hello World!"
></TextView>

También es usual escribir una etiqueta de elemento vacío en la menor cantidad de líneas posible y combinar el final de la etiqueta con la línea anterior a ella. Por lo tanto, es posible que veas una etiqueta de elemento vacío en dos líneas (o incluso en una línea si no tiene atributos):

<!-- with attributes, two lines -->
<TextView
    android:text="Hello World!" />

El elemento ConstraintLayout se escribe con etiquetas de inicio y fin separadas, ya que debe ser capaz de contener otros elementos dentro de él. Esta es una versión simplificada del elemento ConstraintLayout que contiene el elemento TextView:

<androidx.constraintlayout.widget.ConstraintLayout>
    <TextView
        android:text="Hello World!" />
</androidx.constraintlayout.widget.ConstraintLayout>

Si quisieras agregar otra View como elemento secundario del ConstraintLayout, como un Button debajo de la TextView, se escribiría después del final de la etiqueta /> de la TextView y antes de la etiqueta de fin del ConstraintLayout, como se muestra a continuación:

<androidx.constraintlayout.widget.ConstraintLayout>
    <TextView
        android:text="Hello World!" />
    <Button
        android:text="Calculate" />
</androidx.constraintlayout.widget.ConstraintLayout>

Más información sobre XML para diseños

  1. Mira la etiqueta ConstraintLayout y observa que dice androidx.constraintlayout.widget.ConstraintLayout en lugar de solo ConstraintLayout, como la TextView. Esto se debe a que ConstraintLayout es parte de Android Jetpack, que contiene bibliotecas de código que ofrecen funciones adicionales además de la plataforma principal de Android. Jetpack tiene funcionalidades útiles que puedes aprovechar a fin de facilitar la compilación de apps. Reconocerás que este componente de la IU es parte de Jetpack porque comienza con "androidx".
  2. Es posible que hayas notado las líneas que comienzan con xmlns:, seguidas de android, app y tools.
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"

El xmlns se refiere al espacio de nombres XML, y cada línea define un esquema o vocabulario para atributos relacionados con esas palabras. El espacio de nombres android:, por ejemplo, marca atributos definidos por el sistema Android. Todos los atributos del XML del diseño comienzan con uno de esos espacios de nombres.

  1. El espacio en blanco entre elementos XML no cambia el significado para la computadora, pero puede facilitar la lectura del XML.

Android Studio agregará automáticamente espacios en blanco y sangría para facilitar la lectura. Más adelante, aprenderás a hacer que Android Studio se asegure de que tu XML cumpla con las convenciones de estilo de programación.

  1. Puedes agregar comentarios al XML, tal como lo harías con el código Kotlin. Inicia con <!-- y termina con -->.
<!-- this is a comment in XML -->

<!-- this is a
multi-line
Comment.
And another
Multi-line comment -->
  1. Observa la primera línea del archivo:
<?xml version="1.0" encoding="utf-8"?>

Esto indica que el archivo es un archivo en formato XML, pero no todos estos archivos lo incluyen.

4. Compila el diseño en XML

  1. Aún en activity_main.xml, cambia a la vista Split de la pantalla para ver el XML junto al editor de diseño. El editor de diseño te permite obtener una vista previa del diseño de la IU.

a03bcf5beacb4b45.png

  1. Puedes usar la vista que quieras. Sin embargo, para este codelab, deberás usar la de Split para poder ver el XML que estás editando y los cambios correspondientes en el editor de diseño.
  2. Prueba hacer clic en diferentes líneas (una debajo del ConstraintLayout y, luego, otra debajo de la TextView) y observa que la vista correspondiente se seleccionará en el editor de diseño. La inversa también funciona; por ejemplo, si haces clic en la TextView, en el editor de diseño, se destacará el XML correspondiente.

1abc54a646c39f66.png

Borra el elemento TextView

  1. Ya no necesitas la TextView, así que bórrala. Asegúrate de borrar todo desde <TextView hasta el /> de cierre.
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

Todo lo que queda en el archivo es el ConstraintLayout:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Agrega un padding de 16 dp al ConstraintLayout de modo que la IU no quede pegada al borde de la pantalla.

El padding es similar a los márgenes, pero agrega espacio interno al ConstraintLayout en lugar de agregar espacio externo.

<androidx.constraintlayout.widget.ConstraintLayout
    ...
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

Agrega un campo de texto para el costo del servicio

En este paso, agregarás el elemento de la IU de modo que el usuario pueda ingresar el costo del servicio en la app. Usarás un elemento EditText, que le permitirá al usuario ingresar o modificar texto en una app.

7746dedb0d79923f.png

  1. Consulta la documentación de EditText y revisa el XML de muestra.
  2. Busca un espacio en blanco entre las etiquetas de inicio y fin del ConstraintLayout.
  3. Copia y pega el XML de la documentación en ese espacio de tu diseño en Android Studio.

El archivo de diseño debería tener el siguiente aspecto:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/plain_text_input"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:inputType="text"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Es posible que aún no entiendas todo esto, pero lo explicaremos en los siguientes pasos.

  1. Observa que EditText aparece subrayado en rojo.
  2. Coloca el cursor sobre él y verás el error "view is not constrained" (la vista no está restringida), el cual debería resultarte conocido de codelabs anteriores. Recuerda que los elementos secundarios de un ConstraintLayout necesitan restricciones de modo que el diseño sepa cómo organizarlos.

40c17058bd6786f.png

  1. Agrega estas restricciones al EditText para anclarlo en la esquina superior izquierda del elemento superior.
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

Si estás escribiendo en inglés o en otro idioma que se escriba de izquierda a derecha (LTR), el borde inicial será la izquierda. Sin embargo, algunos idiomas, como el árabe, se escriben de derecha a izquierda (RTL), por lo que el borde inicial será el derecho. Por eso, la restricción usa "start" (inicio) de modo que pueda funcionar tanto con los idiomas LTR como con aquellos RTL. Del mismo modo, las restricciones usan "end" (fin) en lugar de derecha.

A partir de las nuevas restricciones agregadas, el elemento EditText se verá de la siguiente manera:

<EditText
    android:id="@+id/plain_text_input"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:inputType="text"/>

Revisa los atributos de EditText

Vuelve a verificar todos los atributos de EditText que pegaste a fin de asegurarte de que funcione para la manera en que se usará en tu app.

  1. Busca el atributo id, que está establecido en @+id/plain_text_input.
  2. Cambia el atributo id por un nombre más adecuado: @+id/cost_of_service.
  1. Observa el atributo layout_height. Se estableció en wrap_content, lo que significa que la altura será igual a la de su contenido. Eso está bien, ya que solo habrá 1 línea de texto.
  2. Observa el atributo layout_width. Se estableció en match_parent, pero no puedes establecer match_parent en un elemento secundario de ConstraintLayout. Además, no es necesario que el campo de texto sea tan ancho. Establécelo en un ancho fijo de 160dp, con el espacio suficiente para que el usuario ingrese un costo de servicio.

1f82a5e86ae94fd2.png

  1. Observa el atributo inputType: esto es algo nuevo. El valor del atributo es "text", lo cual significa que el usuario puede ingresar cualquier tipo de caracteres de texto en el campo en pantalla (caracteres alfanuméricos, símbolos, etc.).
android:inputType="text"

Sin embargo, querrás que solo escriban números en el EditText, ya que el campo representa un valor monetario.

  1. Borra la palabra text, pero deja las comillas.
  2. Comienza a escribir number en su lugar. Después de escribir "n", Android Studio muestra una lista de finalizaciones posibles que incluyan "n".

99b04cbd21e74693.gif

  1. Elige numberDecimal, que limita la entrada a números con un punto decimal.
android:inputType="numberDecimal"

Para ver otras opciones de tipos de entrada, consulta Especifica el tipo de método de entrada en la documentación para desarrolladores.

Solo queda un cambio más por hacer, ya que resulta útil mostrar alguna sugerencia sobre lo que el usuario debe ingresar en este campo.

  1. Agrega un atributo hint al EditText que describa lo que el usuario debe ingresar en el campo.
android:hint="Cost of Service"

También verás la actualización en el editor de diseño.

824454d2a316efb1.png

  1. Ejecuta tu app en el emulador. Debe tener el siguiente aspecto:

c9d413de53b0853d.png

¡Buen trabajo! Aún no es mucho, pero este es un buen comienzo, y lograste editar algunos XML. El XML de tu diseño debería tener un aspecto similar al que se muestra a continuación:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/cost_of_service"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:hint="Cost of Service"
        android:inputType="numberDecimal"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Agrega la pregunta sobre el servicio

En este paso, agregarás una TextView para mostrar esta pregunta: "¿Qué tal estuvo el servicio?". Intenta escribir esto sin copiar y pegar. Las sugerencias de Android Studio deberían ayudarte.

  1. Después del cierre de la etiqueta EditText, />, agrega una nueva línea y comienza a escribir <TextView.
  2. Selecciona TextView entre las sugerencias, y Android Studio agregará automáticamente los atributos layout_width y layout_height a la TextView.
  3. Selecciona wrap_content para ambos, ya que solo necesitas que la TextView sea tan grande como el contenido de texto en ella. fee18cc43df85294.png
  4. Agrega "How was the service?" al atributo text.
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="How was the service?"
  1. Cierra la etiqueta con />.
  2. En el editor de diseño, observa que la TextView se superpone con el EditText.

ac09d5cae6ae2455.png

Eso no se ve bien, así que deberás agregar restricciones en la TextView. Piensa en las restricciones que necesitas. ¿En qué posición horizontal y vertical deberías colocar la TextView? La captura de pantalla de la app puede ayudarte.

bcc5260318477c14.png

Con respecto a la posición vertical, querrás que TextView esté por debajo del campo de texto para el costo del servicio. En términos de la posición horizontal, querrás que la TextView esté alineada con el borde inicial del elemento superior.

  1. Agrega una restricción horizontal a la TextView para restringir su borde inicial a aquel del elemento superior.
app:layout_constraintStart_toStartOf="parent"
  1. Agrega una restricción vertical a la TextView a fin de restringir el borde superior de la TextView al inferior de la View con el costo del servicio.
app:layout_constraintTop_toBottomOf="@id/cost_of_service"

Observa que @id/cost_of_service no contiene ningún signo de suma porque el ID ya está definido.

3822136f7ed815f2.png

El aspecto no es el mejor, pero de momento no te preocupes por eso. Solo debes asegurarte de que todas las partes necesarias estén en la pantalla y de que la funcionalidad no tenga problemas. Podrás corregir el aspecto en los siguientes codelabs.

  1. Agrega un ID de recurso en la TextView. Deberás consultar esta vista más adelante a medida que agregues más vistas y apliques restricciones entre ellas.
android:id="@+id/service_question"

En este punto, tu XML debería verse de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/cost_of_service"
        android:hint="Cost of Service"
        android:layout_height="wrap_content"
        android:layout_width="160dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:inputType="numberDecimal"/>

    <TextView
        android:id="@+id/service_question"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="How was the service?"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/cost_of_service"/>

</androidx.constraintlayout.widget.ConstraintLayout>

5. Agrega opciones de propinas

A continuación, agregarás botones de selección para las distintas opciones de propina que puede elegir el usuario.

Debería haber tres opciones:

  • Asombrosa (20%)
  • Buena (18%)
  • Aceptable (15%)

Si no sabes cómo hacer esto, puedes hacer una búsqueda en Google. Esta es una excelente herramienta que los desarrolladores usan cuando no pueden avanzar.

  1. Realiza una búsqueda en Google de radio button android. El primer resultado es una guía del sitio para desarrolladores de Android que explica cómo usar los botones de selección. ¡Genial!

f5f1c6778ae7a5d.png

  1. Lee rápidamente la guía de botones de selección.

Al leer la descripción, puedes confirmar que puedes usar un RadioButton como elemento de la IU en tu diseño para cada botón de selección que necesites. Además, deberás agrupar los botones de selección dentro de un RadioGroup, ya que solo se deberá seleccionar una opción por vez.

Hay algunos XML que parecen adaptarse a tus necesidades. Revísalos y observa que RadioGroup es la vista superior y los RadioButtons son vistas secundarias dentro de esa vista superior.

  1. Vuelve a tu diseño en Android Studio y agrega el RadioGroup y el RadioButton a tu app.
  2. Después del elemento TextView, pero aún dentro del ConstraintLayout, comienza a escribir <RadioGroup. Android Studio te proporcionará sugerencias útiles para ayudarte a completar tu XML. aee75ba409dc51aa.png
  3. Establece el layout_width y la layout_height del RadioGroup en wrap_content.
  4. Agrega un ID de recurso configurado como @+id/tip_options.
  5. Cierra la etiqueta de inicio con >.
  6. Android Studio agregará </RadioGroup>. Al igual que el ConstraintLayout, el elemento RadioGroup tendrá otros elementos dentro de él, por lo que quizás quieras moverlo a su propia línea. Cómo configurar el ancho y la altura del diseño para ajustar el contenido
  7. Restringe el RadioGroup debajo de la pregunta sobre el servicio (de forma vertical) y al comienzo del elemento superior (de forma horizontal).
  8. Establece el atributo android:orientation en vertical. Si deseas los RadioButtons en una fila, debes establecer la orientación en horizontal.

El XML del RadioGroup debería verse así:

<RadioGroup
    android:id="@+id/tip_options"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/service_question">

</RadioGroup>

Agrega RadioButtons

  1. Después del último atributo del RadioGroup, pero antes de la etiqueta de fin </RadioGroup>, agrega un RadioButton.
<RadioGroup
    android:id="@+id/tip_options"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/service_question">

    <!-- add RadioButtons here -->

</RadioGroup>
  1. Establece el layout_width y la layout_height en wrap_content.
  2. Asigna un ID de recurso de @+id/option_twenty_percent al RadioButton.
  3. Configura el texto en Amazing (20%).
  4. Cierra la etiqueta con />.
<RadioGroup
   android:id="@+id/tip_options"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   app:layout_constraintTop_toBottomOf="@id/service_question"
   app:layout_constraintStart_toStartOf="parent"
   android:orientation="vertical">

   <RadioButton
       android:id="@+id/option_twenty_percent"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Amazing (20%)" />

</RadioGroup>

53cb416b368e9612.png

Ahora que agregaste un RadioButton, ¿puedes modificar el XML para agregar 2 botones de selección adicionales para las opciones Good (18%) y Okay (15%)?

Así se ve el XML del RadioGroup y los RadioButtons:

<RadioGroup
   android:id="@+id/tip_options"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   app:layout_constraintTop_toBottomOf="@id/service_question"
   app:layout_constraintStart_toStartOf="parent"
   android:orientation="vertical">

   <RadioButton
       android:id="@+id/option_twenty_percent"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Amazing (20%)" />

   <RadioButton
       android:id="@+id/option_eighteen_percent"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Good (18%)" />

   <RadioButton
       android:id="@+id/option_fifteen_percent"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Okay (15%)" />

</RadioGroup>

bab25b6a35d4ce52.png

Agrega una selección predeterminada

Actualmente, ninguna de las opciones de propina está seleccionada. Sería bueno seleccionar una de las opciones del botón de selección de forma predeterminada.

Hay un atributo en el RadioGroup en el que puedes especificar el botón que debe estar marcado en un principio. Se llama checkedButton. Establécelo en el ID de recurso del botón de selección que deseas que esté seleccionado.

  1. En el RadioGroup, establece el atributo android:checkedButton en @id/option_twenty_percent.
<RadioGroup
   android:id="@+id/tip_options"
   android:checkedButton="@id/option_twenty_percent"
   ...

En el editor de diseño, observa que se actualizó el diseño. La opción de la propina de 20% está seleccionada de forma predeterminada. ¡Bien! Ya comienza a parecerse a una calculadora de propinas.

c412e7f16590cd33.png

Así se ve el XML hasta el momento:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/cost_of_service"
        android:hint="Cost of Service"
        android:layout_height="wrap_content"
        android:layout_width="160dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:inputType="numberDecimal"/>

    <TextView
        android:id="@+id/service_question"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="How was the service?"
        app:layout_constraintTop_toBottomOf="@id/cost_of_service"
        app:layout_constraintStart_toStartOf="parent" />

    <RadioGroup
        android:id="@+id/tip_options"
        android:checkedButton="@id/option_twenty_percent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/service_question"
        app:layout_constraintStart_toStartOf="parent"
        android:orientation="vertical">

        <RadioButton
            android:id="@+id/option_twenty_percent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Amazing (20%)" />

        <RadioButton
            android:id="@+id/option_eighteen_percent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Good (18%)" />

        <RadioButton
            android:id="@+id/option_fifteen_percent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Okay (15%)" />
    </RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>

6. Completa el resto del diseño

Ya llegaste a la última parte del diseño. Agregarás un Switch, un Button y una TextView para mostrar el importe de la propina.

bcc5260318477c14.png

Agrega un Switch para redondear la propina

A continuación, usarás un widget de Switch con el fin de permitir que el usuario seleccione Sí o No a efectos de redondear la propina.

Querrás que el Switch sea tan ancho como el elemento superior. Por lo tanto, quizás creas que el ancho debe establecerse en match_parent. Como se señaló con anterioridad, no puedes establecer match_parent en los elementos de la IU de un ConstraintLayout. En cambio, deberás limitar los bordes inicial y final de la vista, y establecer el ancho en 0dp. Si estableces el ancho en 0dp, le indicarás al sistema que no calcule el ancho, sino que solo intente hacer coincidir las restricciones presentes en la vista.

  1. Agrega un elemento Switch después del XML para el RadioGroup.
  2. Como se indicó más arriba, establece el layout_width en 0dp.
  3. Establece la layout_height en wrap_content. Esto hará que la vista Switch sea tan alta como el contenido dentro de ella.
  4. Establece el atributo id en @+id/round_up_switch.
  5. Establece el atributo text en Round up tip?. Se usará como etiqueta del Switch.
  6. Restringe el borde de inicio del Switch a aquel de las tip_options y el borde final al fin del elemento superior.
  7. Restringe la parte superior del Switch a la inferior de las tip_options.
  8. Cierra la etiqueta con />.

Sería bueno que el interruptor esté activo de forma predeterminada, y hay un atributo para ello, android:checked, cuyos valores posibles son true (activado) y false (desactivado).

  1. Establece el atributo android:checked en true.

Con todo esto, el XML del elemento Switch se verá de la siguiente manera:

<Switch
    android:id="@+id/round_up_switch"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:checked="true"
    android:text="Round up tip?"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="@id/tip_options"
    app:layout_constraintTop_toBottomOf="@id/tip_options" />

d374fab984650296.png

Agrega el botón Calculate

A continuación, agregarás un Button de modo que el usuario pueda solicitar que se calcule la propina. Querrás que el botón sea tan ancho como el elemento superior, por lo que las restricciones horizontales y verticales serán las mismas que las del Switch.

  1. Agrega un Button después del Switch.
  2. Establece el ancho en 0dp, como hiciste para el Switch.
  3. Configura el alto en wrap_content.
  4. Asígnale un ID de recurso de @+id/calculate_button, con el texto "Calculate".
  5. Restringe el borde superior de Button al borde inferior de la pregunta ¿Redondear propina? del Switch.
  6. Restringe los bordes de inicio y fin a aquellos del elemento superior.
  7. Cierra la etiqueta con />.

A continuación, te mostramos cómo se ve el XML del Button Calculate:

<Button
   android:id="@+id/calculate_button"
   android:layout_width="0dp"
   android:layout_height="wrap_content"
   android:text="Calculate"
   app:layout_constraintTop_toBottomOf="@id/round_up_switch"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintEnd_toEndOf="parent" />

5338cf87c61d15c9.png

Agrega la propina resultante

Ya casi terminas el diseño. En este paso, agregarás un elemento TextView para el resultado de la propina, ubicado debajo del botón Calculate y alineado con el fin, en lugar de hacerlo con el inicio como los demás elementos de la IU.

  1. Agrega una TextView con un ID de recurso llamado tip_result y el texto Tip Amount.
  2. Restringe el borde final de la TextView a aquel del elemento superior.
  3. Restringe el borde superior al inferior del botón Calculate.
<TextView
    android:id="@+id/tip_result"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toBottomOf="@id/calculate_button"
    android:text="Tip Amount" />

9644bcdabbd8d7d1.png

  1. Ejecuta la app. Debería verse como esta captura de pantalla.

e4ed552fa9fbe4ce.png

Excelente trabajo, en especial si es la primera vez que trabajas con XML.

Ten en cuenta que la app puede no verse exactamente igual que la captura de pantalla, ya que las plantillas pueden haber cambiado en una versión posterior de Android Studio. El botón Calculate todavía no funciona, pero puedes escribir el costo, seleccionar el porcentaje de la propina y activar o desactivar la opción de redondeo de la propina. En el próximo codelab, harás que el botón Calculate funcione, así que asegúrate de hacerlo.

7. Cómo implementar prácticas recomendadas de codificación

Extrae las strings

Es posible que hayas notado las advertencias sobre strings hard-coded. En función de los codelabs anteriores, recuerda que extraer strings en un archivo de recursos facilita que traduzcas de tu app a otros idiomas y que vuelvas a usar strings. Revisa activity_main.xml y extrae todos los recursos de strings.

  1. Haz clic en una string. Coloca el cursor sobre el ícono de bombilla amarilla que aparece y luego haz clic en el triángulo que aparece a su lado. Selecciona Extract String Resource. Los nombres predeterminados de los recursos de cadenas están bien. Si quieres, para las opciones de propina, puedes usar amazing_service, good_service y ok_service de modo que los nombres resulten más descriptivos.

Ahora, verifica los recursos de cadenas que acabas de agregar.

  1. Si no se muestra la ventana Project, haz clic en la pestaña Project del lado izquierdo de la ventana.
  2. Abre app > res > values > strings.xml a fin de ver todos los recursos de strings de la IU.
<resources>
    <string name="app_name">Tip Time</string>
    <string name="cost_of_service">Cost of Service</string>
    <string name="how_was_the_service">How was the service?</string>
    <string name="amazing_service">Amazing (20%)</string>
    <string name="good_service">Good (18%)</string>
    <string name="ok_service">Okay (15%)</string>
    <string name="round_up_tip">Round up tip?</string>
    <string name="calculate">Calculate</string>
    <string name="tip_amount">Tip Amount</string>
</resources>

Cambia el formato del XML

Android Studio proporciona varias herramientas para ordenar tu código y garantizar que cumpla con las convenciones de programación recomendadas.

  1. En activity_main.xml, elige Edit > Select All.
  2. Selecciona Code > Reformat Code.

Esto asegurará que la sangría sea coherente y quizás reorganice algunos de los XML de los elementos de la IU con el fin de agrupar las cosas, por ejemplo, uniendo todos los atributos android: de un elemento.

8. Código de solución

bcc5260318477c14.png

res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/cost_of_service"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:hint="@string/cost_of_service"
        android:inputType="numberDecimal"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/service_question"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/how_was_the_service"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/cost_of_service" />

    <RadioGroup
        android:id="@+id/tip_options"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checkedButton="@id/option_twenty_percent"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/service_question">

        <RadioButton
            android:id="@+id/option_twenty_percent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/amazing_service" />

        <RadioButton
            android:id="@+id/option_eighteen_percent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/good_service" />

        <RadioButton
            android:id="@+id/option_fifteen_percent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/ok_service" />
    </RadioGroup>

    <Switch
        android:id="@+id/round_up_switch"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="@string/round_up_tip"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@id/tip_options"
        app:layout_constraintTop_toBottomOf="@id/tip_options" />

    <Button
        android:id="@+id/calculate_button"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="@string/calculate"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/round_up_switch" />

    <TextView
        android:id="@+id/tip_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tip_amount"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/calculate_button" />
</androidx.constraintlayout.widget.ConstraintLayout>

res/values/strings.xml

<resources>
   <string name="app_name">Tip Time</string>
   <string name="cost_of_service">Cost of Service</string>
   <string name="how_was_the_service">How was the service?</string>
   <string name="amazing_service">Amazing (20%)</string>
   <string name="good_service">Good (18%)</string>
   <string name="ok_service">Okay (15%)</string>
   <string name="round_up_tip">Round up tip?</string>
   <string name="calculate">Calculate</string>
   <string name="tip_amount">Tip Amount</string>
</resources>

9. Resumen

  • El XML (lenguaje de marcación extensible) es una forma de organizar el texto, formado por etiquetas, elementos y atributos.
  • Usa XML a efectos de definir el diseño de una app para Android.
  • Usa EditText a fin de permitir al usuario ingresar o editar texto.
  • Un EditText puede contar con una sugerencia que le indique al usuario lo que se espera ingresar en ese campo.
  • Especifica el atributo android:inputType para limitar el tipo de texto que el usuario puede ingresar en un campo EditText.
  • Haz una lista de opciones exclusivas con RadioButtons, agrupadas con un RadioGroup.
  • Un RadioGroup puede ser vertical u horizontal, y puedes especificar qué RadioButton debe aparecer seleccionado inicialmente.
  • Usa un Switch con el fin de permitir que el usuario active o desactive dos opciones.
  • Puedes agregar una etiqueta a un Switch sin usar una TextView independiente.
  • Cada elemento secundario de un ConstraintLayout debe tener restricciones verticales y horizontales.
  • Usa las restricciones de "inicio" y "fin" para controlar los idiomas que se leen de izquierda a derecha (LTR) y de derecha a izquierda (RTL).
  • Los nombres de los atributos de restricción siguen el formato layout_constraint<Source>_to<Target>Of.
  • Para hacer que una View sea tan ancha como el ConstraintLayout en el que se encuentra, restringe el inicio y el fin a aquellos del elemento superior y establece el ancho en 0 dp.

10. Más información

A continuación, se incluyen vínculos a documentación adicional sobre los temas que revisamos. Puedes encontrar toda la documentación para el desarrollo de Android en developer.android.com. Y no olvides que puedes realizar una búsqueda en Google si en algún momento no puedes avanzar.

11. Practica por tu cuenta

Haz lo siguiente:

  • Crea una app de calculadora diferente, como un conversor de unidades para cocinar, a fin de alternar entre mililitros y onzas líquidas, gramos y tazas, etc. ¿Qué campos necesitas?