Los componentes de Material (MDC) ayudan a los desarrolladores a implementar Material Design. MDC, creado por un equipo de ingenieros y diseñadores de UX en Google, cuenta con decenas de componentes de IU atractivos y funcionales, y está disponible para Android, iOS, la Web y Flutter. material.io/develop |
¿Qué son Material Design y los componentes de Material para Android?
Material Design es un sistema para crear productos digitales atractivos y llamativos. Mediante la unión de estilo, desarrollo de la marca, interacción y movimiento en un conjunto coherente de principios y componentes, los equipos de productos pueden alcanzar su máximo potencial de diseño.
En el caso de las aplicaciones para Android, los componentes de Material para Android (MDC para Android) agrupan el diseño y la ingeniería en una biblioteca de componentes a fin de crear coherencia entre las aplicaciones. A medida que evoluciona el sistema de Material Design, se actualizan estos componentes para garantizar la implementación coherente y perfecta de píxeles, y los estándares de desarrollo del frontend de Google. MDC también está disponible para la Web, iOS y Flutter.
En este codelab, crearás una página de acceso con varios de los componentes de MDC de Android.
Qué compilarás
Este codelab es el primero de 4 que te guiarán para que compiles una app llamada Shrine, una app de comercio electrónico para Android que vende ropa y artículos para el hogar. Demostrará cómo puedes personalizar los componentes para que reflejen cualquier marca o estilo con MDC-Android.
En este codelab, crearás una página de acceso para Shrine que contiene lo siguiente:
- Dos campos de texto: uno para ingresar un nombre de usuario y el otro para la contraseña
- Dos botones, uno para “Cancelar” y otro para “Siguiente”
- El nombre de la app (Shine)
- Una imagen del logotipo de Shrine
Componentes de MDC de Android en este codelab
- Campo de texto
- Botón
Requisitos
- Conocimientos básicos sobre el desarrollo para Android
- Android Studio (descárgala aquí si aún no lo tienes).
- Un emulador o dispositivo Android (disponible a través de Android Studio)
- El código de muestra (consulta el siguiente paso)
¿Cómo calificarías tu nivel de experiencia con la compilación de apps para Android?
Inicia Android Studio
Cuando abras Android Studio, debería aparecer una ventana con el título "Welcome to Android Studio". Sin embargo, si es la primera vez que inicias Android Studio, sigue los pasos del asistente de configuración de Android Studio con los valores predeterminados. En este paso, descargar e instalar los archivos necesarios puede tardar varios minutos. Puedes permitir que se ejecute en segundo plano mientras realizas los pasos de la siguiente sección.
Descarga la app de inicio del codelab
La app de inicio se encuentra en el directorio material-components-android-codelabs-101-starter/java
.
… o clónalo desde GitHub
Para clonar este codelab desde GitHub, ejecuta los siguientes comandos:
git clone https://github.com/material-components/material-components-android-codelabs cd material-components-android-codelabs/ git checkout 101-starter
Cómo cargar el código de inicio en Android Studio
- Una vez que finalice el asistente de configuración y aparezca la ventana Welcome to Android Studio, haz clic en Open an existing Android Studio project. Navega al directorio en el que instalaste el código de muestra y selecciona java -> santuario (o busca shrine en tu computadora) para abrir el proyecto de Shrine.
- Espera un momento para que Android Studio compile y sincronice el proyecto, como se muestra en los indicadores de actividad de la parte inferior de la ventana de Android Studio.
- En este punto, es posible que Android Studio genere algunos errores de compilación, ya que te faltan el SDK de Android o las herramientas de compilación, como se muestra más abajo. Sigue las instrucciones de Android Studio para instalar o actualizar estos elementos y sincronizar tu proyecto.
Cómo agregar dependencias de proyectos
El proyecto necesita una dependencia en la biblioteca de compatibilidad de MDC de Android. El código de muestra que descargaste ya debería tener esta dependencia, pero se recomienda realizar los siguientes pasos para asegurarte de que suceda.
- Navega hasta el archivo
build.gradle
del móduloapp
y asegúrate de que el bloquedependencies
incluya una dependencia en MDC para Android:
api 'com.google.android.material:material:1.1.0-alpha06'
- (Opcional) Si es necesario, edita el archivo
build.gradle
para agregar las siguientes dependencias y sincronizar el proyecto.
dependencies { api 'com.google.android.material:material:1.1.0-alpha06' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.android.volley:volley:1.1.1' implementation 'com.google.code.gson:gson:2.8.5' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test:runner:1.2.0-alpha05' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha05' }
Cómo ejecutar la app de inicio
|
¡Listo! El código de inicio para la página de acceso de Shrine debe ejecutarse en tu emulador. Deberías ver el nombre "Shrine" y el logotipo de Shrine justo debajo.
Echemos un vistazo al código. Proporcionamos un framework de navegación Fragment
simple en nuestro código de muestra para mostrar fragmentos y navegar entre fragmentos.
Abre MainActivity.java
en el directorio shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine
. Debe contener lo siguiente:
MainActivity.java
package com.google.codelabs.mdc.java.shrine;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
public class MainActivity extends AppCompatActivity implements NavigationHost {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shr_main_activity);
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container, new LoginFragment())
.commit();
}
}
/**
* Navigate to the given fragment.
*
* @param fragment Fragment to navigate to.
* @param addToBackstack Whether or not the current fragment should be added to the backstack.
*/
@Override
public void navigateTo(Fragment fragment, boolean addToBackstack) {
FragmentTransaction transaction =
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment);
if (addToBackstack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
}
Esta actividad muestra el archivo de diseño R.layout.shr_main_activity
, definido en shr_main_activity.xml
.
Puedes ver que, en onCreate(),
, MainActivity.java
inicia una transacción Fragment
para mostrar la LoginFragment
. LoginFragment.
Eso es lo que modificaremos en este codelab. La actividad también implementa un método navigateTo(Fragment)
, definido en NavigationHost
, que permite que cualquier fragmento navegue a un fragmento diferente.
Comando + clic (o Control + clic) shr_main_activity
en el archivo de actividad para abrir el archivo de diseño o navega al archivo de diseño en app -> res -> layout -> shr_main_activity.xml
.
shr_main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
Aquí, vemos un <FrameLayout>
simple que actúa como contenedor de cualquier fragmento que muestra la actividad. Abramos LoginFragment.java
.
LoginFragment.java
package com.google.codelabs.mdc.java.shrine;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
/**
* Fragment representing the login screen for Shrine.
*/
public class LoginFragment extends Fragment {
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.shr_login_fragment, container, false);
// Snippet from "Navigate to the next Fragment" section goes here.
return view;
}
// "isPasswordValid" from "Navigate to the next Fragment" section method goes here
}
LoginFragment
aumenta el archivo de diseño shr_login_fragment
y lo muestra en onCreateView()
. Echemos un vistazo al archivo de diseño shr_login_fragment.xml
para comprobar cómo se ve la página de acceso.
shr_login_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:background="@color/loginPageBackgroundColor"
tools:context=".LoginFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
android:padding="24dp"
android:paddingTop="16dp">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="48dp"
android:layout_marginBottom="16dp"
app:srcCompat="@drawable/shr_logo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="132dp"
android:text="@string/shr_app_name"
android:textAllCaps="true"
android:textSize="16sp" />
<!-- Snippet from "Add text fields" section goes here. -->
<!-- Snippet from "Add buttons" section goes here. -->
</LinearLayout>
</ScrollView>
Aquí, podemos ver un <LinearLayout>
con una <ImageView>
en la parte superior, que representa el logotipo de "Shrine".
Luego, hay una etiqueta <TextView>
que representa la etiqueta "SHRINE". El texto de esta etiqueta es un recurso de strings llamado @string/shr_app_name
. Si Comando + clic (o Control + clic) en el nombre del recurso de strings o abres app -> res -> values -> strings.xml
, puedes ver el archivo strings.xml
en el que se definen los recursos de strings. Aquí se definirán cuando se agreguen más recursos de strings. Todos los recursos de este archivo deben tener un prefijo shr_
para indicar que forman parte de la app de Shrine.
Ahora que conoces el código de inicio, implementemos el primer componente.
Para comenzar, agregaremos dos campos de texto a nuestra página de acceso para que las personas ingresen su nombre de usuario y contraseña. Utilizaremos el componente MDC Text Field, que incluye una funcionalidad integrada que muestra una etiqueta flotante y mensajes de error.
Agrega el XML
En shr_login_fragment.xml
, agrega dos elementos TextInputLayout
con un elemento secundario TextInputEditText
dentro de la etiqueta <LinearLayout>
, debajo de la etiqueta <TextView>
:
shr_login_fragment.xml
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_username">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_password">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
El fragmento anterior representa dos campos de texto, cada uno de los cuales consiste en un elemento <TextInputLayout>
y un elemento secundario <TextInputEditText>
. El texto de sugerencia para cada campo de texto se especifica en el atributo android:hint
.
Incluimos dos recursos de strings nuevos para el campo de texto: @string/shr_hint_username
y @string/shr_hint_password
. Abre strings.xml
para ver estos recursos de string.
strings.xml
...
<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>
...
Cómo agregar una validación de entrada
Los componentes de TextInputLayout
proporcionan una función de comentarios de errores integrada.
Para mostrar comentarios sobre los errores, realiza los siguientes cambios en shr_login_fragment.xml
:
- Establece el atributo
app:errorEnabled
como verdadero en el elemento PasswordTextInputLayout
. De esta manera, se agregará padding adicional para el mensaje de error debajo del campo de texto. - Establece el atributo
android:inputType
entextPassword
en el elemento ContraseñaTextInputEditText
. Esta acción ocultará el texto de entrada en el campo de la contraseña.
Con estos cambios, los campos de texto en shr_login_fragment.xml
deberían verse así:
shr_login_fragment.xml
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_username">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/shr_hint_password"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
Ahora, prueba ejecutar la app. Deberías ver una página con dos campos de texto para "Username" y "Password".
Observa la animación de etiquetas flotantes:
A continuación, agregaremos dos botones a nuestra página de acceso: "Cancel" y "Next". Utilizaremos el componente MDC Button, que viene con el emblemático efecto de ondas de la tinta de Material Design integrado.
Agrega el XML
En shr_login_fragment.xml
, agrega un <RelativeLayout>
al <LinearLayout>
, debajo de los elementos TextInputLayout
. Luego, agrega dos elementos <MaterialButton>
a <RelativeLayout>
.
El archivo XML resultante debería verse de la siguiente manera:
shr_login_fragment.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:text="@string/shr_button_next" />
<com.google.android.material.button.MaterialButton
android:id="@+id/cancel_button"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:layout_toStartOf="@id/next_button"
android:layout_toLeftOf="@id/next_button"
android:text="@string/shr_button_cancel" />
</RelativeLayout>
Listo. Cuando ejecutes la app, se mostrará una onda de tinta cuando presiones cada botón.
Por último, agregaremos un código Java a LoginFragment.java
para conectar nuestro botón "NEXT" a otro fragmento. Notarás que a cada uno de los componentes que agregamos a nuestro diseño se le asignó un elemento id
. Usaremos estos id
para hacer referencia a los componentes de nuestro código y agregar algunas verificaciones de errores y navegación.
Agreguemos un método booleano privado isPasswordValid
en LoginFragment.java
debajo de onCreateView()
, con lógica para determinar si la contraseña es válida o no. Para los fines de esta demostración, solo nos aseguraremos de que la contraseña tenga al menos 8 caracteres:
LoginFragment.java
/*
In reality, this will have more complex logic including, but not limited to, actual
authentication of the username and password.
*/
private boolean isPasswordValid(@Nullable Editable text) {
return text != null && text.length() >= 8;
}
A continuación, agrega un objeto de escucha de clics al botón "Next" que establece y borra el error en función del método isPasswordValid()
que acabamos de crear. En onCreateView()
, este objeto de escucha de clics se debe colocar entre la línea del amplificador y la línea del return view
.
A continuación, agregaremos un objeto de escucha de claves a la contraseña TextInputEditText
para escuchar los eventos clave que podrían borrar el error. Este objeto de escucha también debe usar isPasswordValid()
para verificar si la contraseña es válida. Puedes agregar esta opción directamente debajo del objeto de escucha de clics en onCreateView()
.
Tu método onCreateView() ahora debería ser similar al siguiente:
LoginFragment.java
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.shr_login_fragment, container, false);
final TextInputLayout passwordTextInput = view.findViewById(R.id.password_text_input);
final TextInputEditText passwordEditText = view.findViewById(R.id.password_edit_text);
MaterialButton nextButton = view.findViewById(R.id.next_button);
// Set an error if the password is less than 8 characters.
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isPasswordValid(passwordEditText.getText())) {
passwordTextInput.setError(getString(R.string.shr_error_password));
} else {
passwordTextInput.setError(null); // Clear the error
}
}
});
// Clear the error once more than 8 characters are typed.
passwordEditText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
if (isPasswordValid(passwordEditText.getText())) {
passwordTextInput.setError(null); //Clear the error
}
return false;
}
});
return view;
}
Ahora podemos navegar a otro fragmento. Actualiza el elemento OnClickListener
de onCreateView()
para navegar a otro fragmento cuando la validación de errores se realice correctamente. A fin de lograrlo, agrega la siguiente línea para navegar a ProductGridFragment
hasta el caso de else
del objeto de escucha de clics:
LoginFragment.java
...
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
...
El objeto de escucha de clics debería verse de la siguiente manera:
LoginFragment.java
...
MaterialButton nextButton = view.findViewById(R.id.next_button);
// Set an error if the password is less than 8 characters.
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isPasswordValid(passwordEditText.getText())) {
passwordTextInput.setError(getString(R.string.shr_error_password));
} else {
passwordTextInput.setError(null); // Clear the error
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
}
}
});
...
Esta nueva línea de código llama al método navigateTo()
de MainActivity
para navegar a un fragmento nuevo: ProductGridFragment
. Actualmente, esta es una página vacía en la que trabajarás en MDC-102.
Ahora, compila la app. Presiona el botón Siguiente.
¡Lo logró! Esta pantalla será el punto de partida de nuestro próximo codelab en el que trabajarás en MDC-102.
Mediante el lenguaje de marcado XML básico y aproximadamente 30 líneas de Java, la biblioteca de componentes de Material para Android te ayudó a crear una hermosa página de acceso que cumple con los lineamientos de Material Design, y también tiene un aspecto y comportamiento coherentes en todos los dispositivos.
Próximos pasos
El campo de texto y el botón son dos componentes principales de la biblioteca MDC de Android, pero hay muchos más. Puedes explorar el resto de los componentes de MDC en Android. Como alternativa, consulta MDC 102: Estructura y diseño de Material Design para obtener información sobre la barra superior de la app, la vista de tarjetas y el diseño de la cuadrícula. Gracias por probar los componentes de Material. Esperamos que hayas disfrutado de este codelab.