MDC-102 Android: Estructura de Material y diseño (Kotlin)

1. Introducción

logo_components_color_2x_web_96dp.png

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.

En el codelab MDC-101, usaste dos componentes de Material (MDC) para crear una página de acceso: campos de texto y botones con ondas de tinta. Ahora vamos a agregar navegación, estructura y datos para expandir esta base.

Qué compilarás

En este codelab, compilarás una pantalla principal para una app llamada Shrine, una aplicación de comercio electrónico en la que se vende ropa y artículos para el hogar. Contiene lo siguiente:

  • Una barra superior de la app
  • Una lista de cuadrícula llena de productos

249db074eff043f4.png

Componentes de MDC-Android en este codelab

  • AppBarLayout
  • MaterialCardView

Requisitos

  • Conocimientos básicos de desarrollo de Android
  • Android Studio (descárgalo aquí si todavía 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?

Principiante Intermedio Avanzado

2. Configura tu entorno de desarrollo

¿Vienes de MDC-101?

Si completaste MDC-101, tu código debería estar preparado para este codelab. Avanza al paso 3: Cómo agregar una barra superior de la app.

¿Empiezas de cero?

Descarga la app de inicio del codelab

La app de inicio se encuentra en el directorio material-components-android-codelabs-102-starter/kotlin. Asegúrate de cd en ese directorio antes de comenzar.

… 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 102-starter

Cómo cargar el código de inicio en Android Studio

  1. 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 kotlin -> antiguo (o busca shrine) en tu computadora para abrir el proyecto de envío.
  2. 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.
  3. 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.

KzoYWC1S7Se7yL8igi1vXF_mbVxAdl2lg5kb7RODrsVpEng0G6U3NK1Qnn0faBBZd2u71yMXioy9tD-7fv3NXvVO4N3EtMMeWDTmqBMMl6egd9R5uXX0T_SKmahbmRor3wZZHX0ByA

Agrega dependencias del proyecto

El proyecto necesita una dependencia en la biblioteca de compatibilidad de MDC para Android. El código de muestra que descargaste ya debería tener esta dependencia en la lista, pero te recomendamos que realices los siguientes pasos para asegurarte.

  1. Navega al archivo build.gradle del módulo app y asegúrate de que el bloque dependencies incluya una dependencia en MDC para Android:
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (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

  1. Asegúrate de que la configuración de compilación ubicada a la izquierda del botón Run / Play sea app.
  2. Presiona el botón verde Run/Play para compilar y ejecutar la app.
  3. En la ventana Select Deployment Target, si ya tienes un dispositivo Android en la lista de dispositivos disponibles, ve al Paso 8. De lo contrario, haz clic en Create New Virtual Device.
  4. En la pantalla Select Hardware, selecciona un teléfono (por ejemplo, Pixel 2) y haz clic en Next.
  5. En la pantalla System Image, selecciona una versión reciente de Android, preferentemente, el nivel de API más alto. Si no está instalada, haz clic en el vínculo Download que aparece y completa la descarga.
  6. Haz clic en Next.
  7. En la pantalla Android Virtual Device (AVD) , deja los ajustes tal como están y haz clic en Finish.
  8. Selecciona un dispositivo Android en el diálogo de destino de implementación.
  9. Haz clic en Aceptar.
  10. Android Studio compila la app, la implementa y la abre automáticamente en el dispositivo de destino.

¡Listo! Deberías ver la página de acceso de Shrine del codelab MDC-101.

4cb0c218948144b4.png

Ahora que la pantalla de acceso se ve bien, vamos a propagar la app con algunos productos.

3. Cómo agregar una barra superior de la app

La pantalla principal se revela cuando se descarta la página de acceso, con una pantalla que dice "¡Lo lograste!". Fantástico. Pero ahora nuestro usuario no tiene ninguna acción para realizar ni sabe en qué parte de la app está. Para solucionarlo, es momento de agregar la navegación.

Material Design ofrece patrones de navegación que garantizan un alto grado de usabilidad. Uno de los componentes más visibles es la barra superior de la app.

Para posibilitar la navegación y brindar a los usuarios acceso rápido a otras acciones, agregaremos una barra superior de la app.

Cómo agregar un widget de AppBar

En shr_product_grid_fragment.xml, borra el bloque <LinearLayout> que contiene el mensaje "¡Lo lograste!". TextView y reemplázalo por lo siguiente:

shr_product_grid_fragment.xml

<com.google.android.material.appbar.AppBarLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/app_bar"
       style="@style/Widget.Shrine.Toolbar"
       android:layout_width="match_parent"
       android:layout_height="?attr/actionBarSize"
       app:title="@string/shr_app_name" />
</com.google.android.material.appbar.AppBarLayout>

Tu shr_product_grid_fragment.xml ahora debería verse de la siguiente manera:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

Muchas barras de la app tienen un botón junto al título. Agreguemos un ícono de menú al nuestro.

Cómo agregar un ícono de navegación

Aún en shr_product_grid_fragment.xml, agrega lo siguiente al componente XML Toolbar que acabas de agregar a tu diseño:

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

Tu shr_product_grid_fragment.xml debería verse de la siguiente manera:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ProductGridFragment">
  
   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>
  
</FrameLayout>

Cómo agregar botones de acción y diseñar la barra superior de la app

También puedes agregar botones en el extremo final de la barra de la app. En Android, estos se llaman botones de acción. Diseñaremos la barra superior de la app y agregaremos botones de acción a su menú de forma programática.

En la función onCreateView de ProductGridFragment.kt, configura el Toolbar de activity para que se use como ActionBar con setSupportActionBar. Puedes hacerlo después de que se haya creado la vista con el inflater.

ProductGridFragment.kt

override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
   // Inflate the layout for this fragment with the ProductGrid theme
   val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

   // Set up the toolbar.
   (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

   return view;
}

A continuación, justo debajo del método que acabamos de cambiar para configurar la barra de herramientas, anulemos onCreateOptionsMenu para expandir el contenido de shr_toolbar_menu.xml en la barra de herramientas:

ProductGridFragment.kt

override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
   super.onCreateOptionsMenu(menu, menuInflater)
}

Por último, anula onCreate() en ProductGridFragment.kt y, después de llamar a super(), llama a setHasOptionMenu con true:

ProductGridFragment.kt

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setHasOptionsMenu(true)
}

Los fragmentos de código anteriores configuran la barra de la app de nuestro diseño XML para que sea la barra de acciones de esta actividad. La devolución de llamada onCreateOptionsMenu le indica a la actividad qué usar como menú. En este caso, colocará los elementos de menú de R.menu.shr_toolbar_menu en la barra de la app. El archivo de menú contiene dos elementos: "Buscar" y "Filtro".

shr_toolbar_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/search"
       android:icon="@drawable/shr_search"
       android:title="@string/shr_search_title"
       app:showAsAction="always" />
   <item
       android:id="@+id/filter"
       android:icon="@drawable/shr_filter"
       android:title="@string/shr_filter_title"
       app:showAsAction="always" />
</menu>

Después de esos cambios, tu archivo ProductGridFragment.kt debería verse de la siguiente manera:

ProductGridFragment.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry
import kotlinx.android.synthetic.main.shr_product_grid_fragment.view.*

class ProductGridFragment : Fragment() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setHasOptionsMenu(true)
   }

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment with the ProductGrid theme
       val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

       // Set up the tool bar
       (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

       return view;
   }

   override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
       super.onCreateOptionsMenu(menu, menuInflater)
   }
}

Realiza la compilación y ejecuta la aplicación. La pantalla principal debería verse de la siguiente manera:

d04e8aa3b27f4754.png

Ahora la barra de herramientas tiene un ícono de navegación, un título y dos íconos de acción en el lado derecho. La barra de herramientas también muestra la elevación con una sombra sutil que indica que se encuentra en una capa diferente a la del contenido.

4. Agregar una tarjeta

Ahora que nuestra app tiene cierta estructura, coloquemos el contenido en tarjetas para organizarlo.

Agregar una tarjeta

Comencemos por agregar una tarjeta debajo de la barra superior de la app. Una tarjeta debe tener una región para una imagen, un título y una etiqueta para el texto secundario. Agrega lo siguiente en shr_product_grid_fragment.xml debajo de AppBarLayout.

shr_product_grid_fragment.xml

<com.google.android.material.card.MaterialCardView
   android:layout_width="160dp"
   android:layout_height="180dp"
   android:layout_marginBottom="16dp"
   android:layout_marginLeft="16dp"
   android:layout_marginRight="16dp"
   android:layout_marginTop="70dp"
   app:cardBackgroundColor="?attr/colorPrimaryDark"
   app:cardCornerRadius="4dp">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="bottom"
       android:background="#FFFFFF"
       android:orientation="vertical"
       android:padding="8dp">

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:padding="2dp"
           android:text="@string/shr_product_title"
           android:textAppearance="?attr/textAppearanceHeadline6" />

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:padding="2dp"
           android:text="@string/shr_product_description"
           android:textAppearance="?attr/textAppearanceBody2" />
   </LinearLayout>
</com.google.android.material.card.MaterialCardView>

Compila y ejecuta:

f6184a55ccb5f920.png

En esta vista previa, puedes ver que la tarjeta está insertada desde el borde izquierdo y tiene esquinas redondeadas y una sombra (que expresa la elevación de la tarjeta). Todo el elemento se denomina "contenedor". Aparte del contenedor, todos los elementos que contiene son opcionales.

Puedes agregar los siguientes elementos a un contenedor: texto de encabezado, una miniatura o un avatar, texto de subtítulo, divisores y hasta íconos y botones. Por ejemplo, la tarjeta que acabamos de crear contiene dos TextView (uno para el título y otro para el texto secundario) en un LinearLayout, alineado con la parte inferior de la tarjeta.

Las tarjetas suelen mostrarse en una colección con otras tarjetas. En la siguiente sección de este codelab, los presentaremos como una colección en una cuadrícula.

5. Crea una cuadrícula de tarjetas

Cuando hay varias tarjetas en una pantalla, se agrupan en una o más colecciones. Las tarjetas en una cuadrícula son coplanares, lo que significa que comparten la misma elevación en reposo que las demás (a menos que se recojan o arrastren, pero no abordaremos eso en este codelab).

Configura la cuadrícula de tarjetas

Consulta el archivo shr_product_card.xml que te proporcionamos:

shr_product_card.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   app:cardBackgroundColor="@android:color/white"
   app:cardElevation="2dp"
   app:cardPreventCornerOverlap="true">

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

       <com.android.volley.toolbox.NetworkImageView
           android:id="@+id/product_image"
           android:layout_width="match_parent"
           android:layout_height="@dimen/shr_product_card_image_height"
           android:background="?attr/colorPrimaryDark"
           android:scaleType="centerCrop" />

       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:padding="16dp">

           <TextView
               android:id="@+id/product_title"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="@string/shr_product_title"
               android:textAppearance="?attr/textAppearanceHeadline6" />

           <TextView
               android:id="@+id/product_price"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:text="@string/shr_product_description"
               android:textAppearance="?attr/textAppearanceBody2" />
       </LinearLayout>
   </LinearLayout>
</com.google.android.material.card.MaterialCardView>

Este diseño de tarjeta contiene una tarjeta con una imagen (en este caso, un NetworkImageView, que nos permite cargar y mostrar imágenes desde una URL) y dos TextViews.

A continuación, observa el ProductCardRecyclerViewAdapter que te proporcionamos. Está en el mismo paquete que ProductGridFragment.

ProductCardRecyclerViewAdapter.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry

/**
* Adapter used to show a simple grid of products.
*/
class ProductCardRecyclerViewAdapter(private val productList: List<ProductEntry>) : RecyclerView.Adapter<ProductCardViewHolder>() {

   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductCardViewHolder {
       val layoutView = LayoutInflater.from(parent.context).inflate(R.layout.shr_product_card, parent, false)
       return ProductCardViewHolder(layoutView)
   }

   override fun onBindViewHolder(holder: ProductCardViewHolder, position: Int) {
       // TODO: Put ViewHolder binding code here in MDC-102
   }

   override fun getItemCount(): Int {
       return productList.size
   }
}

La clase de adaptador anterior administra el contenido de nuestra cuadrícula. Para determinar qué debe hacer cada vista con su contenido determinado, pronto escribiremos el código de onBindViewHolder().

En el mismo paquete, también puedes observar ProductCardViewHolder. Esta clase almacena las vistas que afectan el diseño de nuestra tarjeta, de modo que podamos modificarlas más adelante.

ProductCardViewHolder.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.View
import androidx.recyclerview.widget.RecyclerView

class ProductCardViewHolder(itemView: View) //TODO: Find and store views from itemView
   : RecyclerView.ViewHolder(itemView)

Para configurar nuestra cuadrícula, primero debemos quitar el marcador de posición MaterialCardView de shr_product_grid_fragment.xml. A continuación, debes agregar el componente que representa nuestra cuadrícula de tarjetas. En este caso, usaremos un RecyclerView. Agrega el componente RecyclerView a tu shr_product_grid_fragment.xml debajo del componente XML AppBarLayout:

shr_product_grid_fragment.xml

<androidx.core.widget.NestedScrollView
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:layout_marginTop="56dp"
   android:background="@color/productGridBackgroundColor"
   android:paddingStart="@dimen/shr_product_grid_spacing"
   android:paddingEnd="@dimen/shr_product_grid_spacing"
   app:layout_behavior="@string/appbar_scrolling_view_behavior">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/recycler_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</androidx.core.widget.NestedScrollView>

Tu shr_product_grid_fragment.xml debería verse de la siguiente manera:

shr_product_grid_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ProductGridFragment">

   <com.google.android.material.appbar.AppBarLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/app_bar"
           style="@style/Widget.Shrine.Toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           app:navigationIcon="@drawable/shr_menu"
           app:title="@string/shr_app_name" />
   </com.google.android.material.appbar.AppBarLayout>

   <androidx.core.widget.NestedScrollView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_marginTop="56dp"
       android:background="@color/productGridBackgroundColor"
       android:paddingStart="@dimen/shr_product_grid_spacing"
       android:paddingEnd="@dimen/shr_product_grid_spacing"
       app:layout_behavior="@string/appbar_scrolling_view_behavior">

       <androidx.recyclerview.widget.RecyclerView
           android:id="@+id/recycler_view"
           android:layout_width="match_parent"
           android:layout_height="match_parent" />

   </androidx.core.widget.NestedScrollView>

</FrameLayout>

Por último, en onCreateView(), agrega el código de inicialización de RecyclerView a ProductGridFragment.kt después de llamar a setUpToolbar(view) y antes de la sentencia return:

ProductGridFragment.kt

override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
   // Inflate the layout for this fragment with the ProductGrid theme
   val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

   // Set up the toolbar.
   (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

   // Set up the RecyclerView
   view.recycler_view.setHasFixedSize(true)
   view.recycler_view.layoutManager = GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
   val adapter = ProductCardRecyclerViewAdapter(
           ProductEntry.initProductEntryList(resources))
   view.recycler_view.adapter = adapter
   val largePadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing)
   val smallPadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small)
   view.recycler_view.addItemDecoration(ProductGridItemDecoration(largePadding, smallPadding))

   return view;
}

El fragmento de código anterior contiene los pasos de inicialización necesarios para configurar un RecyclerView. Esto incluye la configuración del administrador de diseño de RecyclerView, además de la inicialización y la configuración del adaptador de RecyclerView.

Tu archivo ProductGridFragment.kt ahora debería verse de la siguiente manera:

ProductGridFragment .kt

package com.google.codelabs.mdc.kotlin.shrine

import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.codelabs.mdc.kotlin.shrine.network.ProductEntry
import kotlinx.android.synthetic.main.shr_product_grid_fragment.view.*

class ProductGridFragment : Fragment() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setHasOptionsMenu(true)
   }

   override fun onCreateView(
           inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       // Inflate the layout for this fragment with the ProductGrid theme
       val view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false)

       // Set up the toolbar.
       (activity as AppCompatActivity).setSupportActionBar(view.app_bar)

       // Set up the RecyclerView
       view.recycler_view.setHasFixedSize(true)
       view.recycler_view.layoutManager = GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
       val adapter = ProductCardRecyclerViewAdapter(
               ProductEntry.initProductEntryList(resources))
       view.recycler_view.adapter = adapter
       val largePadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing)
       val smallPadding = resources.getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small)
       view.recycler_view.addItemDecoration(ProductGridItemDecoration(largePadding, smallPadding))

       return view;
   }

   override fun onCreateOptionsMenu(menu: Menu, menuInflater: MenuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu)
       super.onCreateOptionsMenu(menu, menuInflater)
   }
}

Compila y ejecuta:

f9aeab846fc3bb4c.png

Las tarjetas ya están allí. Aún no muestran nada, así que agreguemos algunos datos de productos.

Agrega imágenes y texto

Para cada tarjeta, agrega una imagen, el nombre del producto y el precio. Nuestra abstracción ViewHolder contiene las vistas de cada tarjeta. En nuestro ViewHolder, agrega las tres vistas de la siguiente manera.

ProductCardViewHolder.kt

package com.google.codelabs.mdc.kotlin.shrine

import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

import com.android.volley.toolbox.NetworkImageView

class ProductCardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

   var productImage: NetworkImageView = itemView.findViewById(R.id.product_image)
   var productTitle: TextView = itemView.findViewById(R.id.product_title)
   var productPrice: TextView = itemView.findViewById(R.id.product_price)
}

Actualiza el método onBindViewHolder() en ProductCardRecyclerViewAdapter para establecer el título, el precio y la imagen del producto para cada vista de producto, como se muestra a continuación:

ProductCardRecyclerViewAdapter.kt

override fun onBindViewHolder(holder: ProductCardViewHolder, position: Int) {
   if (position < productList.size) {
       val product = productList[position]
       holder.productTitle.text = product.title
       holder.productPrice.text = product.price
       ImageRequester.setImageFromUrl(holder.productImage, product.url)
   }
}

El código anterior le indica a nuestro adaptador de RecyclerView qué hacer con cada tarjeta mediante un ViewHolder.

Aquí, establece los datos de texto en cada uno de los TextView de ViewHolder y llama a un ImageRequester para obtener una imagen de una URL. ImageRequester es una clase que proporcionamos para tu comodidad y usa la biblioteca Volley (este es un tema fuera del alcance de este codelab, pero no dudes en explorar el código por tu cuenta).

Compilación y ejecución:

249db074eff043f4.png

Nuestros productos ya se muestran en la app.

6. Resumen

Nuestra app tiene un flujo básico que lleva al usuario de la pantalla de acceso a una pantalla principal en la que se pueden ver los productos. Con solo unas pocas líneas de código, agregamos una barra superior de la app con un título y tres botones, y una cuadrícula de tarjetas para presentar el contenido de nuestra app. Ahora, la pantalla principal es simple y funcional, y tiene una estructura básica y contenido de acción.

Próximos pasos

Con la barra superior de la app, las tarjetas, el campo de texto y el botón, ahora usamos cuatro componentes principales de Material Design de la biblioteca de MDC-Android. Puedes visitar el catálogo de MDC-Android para explorar aún más componentes.

Aunque funciona en su totalidad, nuestra app aún no expresa ninguna marca ni estilo en particular. En MDC-103: Temas de Material Design con color, forma, elevación y tipo, personalizaremos el estilo de estos componentes para expresar una marca moderna y llamativa.

Pude completar este codelab con una cantidad de tiempo y esfuerzo razonables.

Totalmente de acuerdo De acuerdo Neutral En desacuerdo Totalmente en desacuerdo

Me gustaría seguir usando los componentes de Material en el futuro.

Totalmente de acuerdo De acuerdo Neutral En desacuerdo Totalmente en desacuerdo