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
- Una computadora con la versión estable más reciente de Android Studio instalada
- Conexión a Internet a fin de acceder a la documentación para desarrolladores de Android
2. Inicia el proyecto
Consulta la calculadora de propinas en Google: https://www.google.com/search?q=tip+calculator
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:
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
- Para comenzar, crea un nuevo proyecto de Kotlin en Android Studio con la plantilla Empty Activity.
- 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.
- 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.
Jerarquía de contención de una app para Android
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>
Veamos un ejemplo real.
- Abre
activity_main.xml
(res > layout > activity_main.xml). - Notarás que la app muestra una
TextView
que dice "Hello World!" dentro de unConstraintLayout
, como viste en proyectos anteriores creados a partir de esta plantilla.
- Encuentra las opciones para las vistas Code, Split y Design en la parte superior derecha del editor de diseño.
- Selecciona la vista Code.
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.
- 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 elConstraintLayout
. ElConstraintLayout
es el elemento superior, y laTextView
es el secundario. Los atributos de cada elemento se muestran con una sangría a efectos de indicar que forman parte de ese elemento. - 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
- Mira la etiqueta
ConstraintLayout
y observa que diceandroidx.constraintlayout.widget.ConstraintLayout
en lugar de soloConstraintLayout
, como laTextView
. Esto se debe a queConstraintLayout
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". - Es posible que hayas notado las líneas que comienzan con
xmlns:
, seguidas deandroid
,app
ytools
.
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.
- 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.
- 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 -->
- 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
- 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.
- 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.
- Prueba hacer clic en diferentes líneas (una debajo del
ConstraintLayout
y, luego, otra debajo de laTextView
) 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 laTextView
, en el editor de diseño, se destacará el XML correspondiente.
Borra el elemento TextView
- 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>
- 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.
- Consulta la documentación de
EditText
y revisa el XML de muestra. - Busca un espacio en blanco entre las etiquetas de inicio y fin del
ConstraintLayout
. - 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.
- Observa que
EditText
aparece subrayado en rojo. - 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.
- 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.
- Busca el atributo
id
, que está establecido en@+id/plain_text_input
. - Cambia el atributo
id
por un nombre más adecuado:@+id/cost_of_service
.
- Observa el atributo
layout_height
. Se estableció enwrap_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. - Observa el atributo
layout_width
. Se estableció enmatch_parent
, pero no puedes establecermatch_parent
en un elemento secundario deConstraintLayout
. Además, no es necesario que el campo de texto sea tan ancho. Establécelo en un ancho fijo de160dp
, con el espacio suficiente para que el usuario ingrese un costo de servicio.
- 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.
- Borra la palabra
text
, pero deja las comillas. - Comienza a escribir
number
en su lugar. Después de escribir "n", Android Studio muestra una lista de finalizaciones posibles que incluyan "n".
- 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.
- Agrega un atributo
hint
alEditText
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.
- Ejecuta tu app en el emulador. Debe tener el siguiente aspecto:
¡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.
- Después del cierre de la etiqueta
EditText
,/>
, agrega una nueva línea y comienza a escribir<TextView
. - Selecciona
TextView
entre las sugerencias, y Android Studio agregará automáticamente los atributoslayout_width
ylayout_height
a laTextView
. - Selecciona
wrap_content
para ambos, ya que solo necesitas que laTextView
sea tan grande como el contenido de texto en ella. - Agrega
"How was the service?"
al atributotext
.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="How was the service?"
- Cierra la etiqueta con
/>
. - En el editor de diseño, observa que la
TextView
se superpone con elEditText
.
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.
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.
- Agrega una restricción horizontal a la
TextView
para restringir su borde inicial a aquel del elemento superior.
app:layout_constraintStart_toStartOf="parent"
- Agrega una restricción vertical a la
TextView
a fin de restringir el borde superior de laTextView
al inferior de laView
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.
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.
- 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.
- 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!
- 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.
- Vuelve a tu diseño en Android Studio y agrega el
RadioGroup
y elRadioButton
a tu app. - Después del elemento
TextView
, pero aún dentro delConstraintLayout
, comienza a escribir<RadioGroup
. Android Studio te proporcionará sugerencias útiles para ayudarte a completar tu XML. - Establece el
layout_width
y lalayout_height
delRadioGroup
enwrap_content
. - Agrega un ID de recurso configurado como
@+id/tip_options
. - Cierra la etiqueta de inicio con
>
. - Android Studio agregará
</RadioGroup>
. Al igual que elConstraintLayout
, el elementoRadioGroup
tendrá otros elementos dentro de él, por lo que quizás quieras moverlo a su propia línea. - Restringe el
RadioGroup
debajo de la pregunta sobre el servicio (de forma vertical) y al comienzo del elemento superior (de forma horizontal). - Establece el atributo
android:orientation
envertical
. Si deseas losRadioButtons
en una fila, debes establecer la orientación enhorizontal
.
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
- Después del último atributo del
RadioGroup
, pero antes de la etiqueta de fin</RadioGroup>
, agrega unRadioButton
.
<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>
- Establece el
layout_width
y lalayout_height
enwrap_content
. - Asigna un ID de recurso de
@+id/option_twenty_percent
alRadioButton
. - Configura el texto en
Amazing (20%)
. - 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>
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>
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.
- En el
RadioGroup
, establece el atributoandroid: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.
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.
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.
- Agrega un elemento
Switch
después del XML para elRadioGroup
. - Como se indicó más arriba, establece el
layout_width
en0dp
. - Establece la
layout_height
enwrap_content
. Esto hará que la vistaSwitch
sea tan alta como el contenido dentro de ella. - Establece el atributo
id
en@+id/round_up_switch
. - Establece el atributo
text
enRound up tip?
. Se usará como etiqueta delSwitch
. - Restringe el borde de inicio del
Switch
a aquel de lastip_options
y el borde final al fin del elemento superior. - Restringe la parte superior del
Switch
a la inferior de lastip_options
. - 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).
- Establece el atributo
android:checked
entrue
.
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" />
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
.
- Agrega un
Button
después delSwitch
. - Establece el ancho en
0dp
, como hiciste para elSwitch
. - Configura el alto en
wrap_content
. - Asígnale un ID de recurso de
@+id/calculate_button
, con el texto"Calculate"
. - Restringe el borde superior de
Button
al borde inferior de la pregunta ¿Redondear propina? delSwitch
. - Restringe los bordes de inicio y fin a aquellos del elemento superior.
- 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" />
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.
- Agrega una
TextView
con un ID de recurso llamadotip_result
y el textoTip Amount
. - Restringe el borde final de la
TextView
a aquel del elemento superior. - 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" />
- Ejecuta la app. Debería verse como esta captura de pantalla.
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.
- 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
yok_service
de modo que los nombres resulten más descriptivos.
Ahora, verifica los recursos de cadenas que acabas de agregar.
- Si no se muestra la ventana Project, haz clic en la pestaña Project del lado izquierdo de la ventana.
- 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.
- En
activity_main.xml
, elige Edit > Select All. - 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
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 campoEditText
. - Haz una lista de opciones exclusivas con
RadioButtons
, agrupadas con unRadioGroup
. - 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 unaTextView
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 elConstraintLayout
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?