MDC-102 Android: estrutura e layout do Material Design (Java)

logo_components_color_2x_web_96dp.png

Os componentes do Material Design (MDC, na sigla em inglês) ajudam os desenvolvedores a implementar o Material Design. Criados por uma equipe de engenheiros e designers de UX do Google, os MDC oferecem dezenas de componentes de IU bonitos e funcionais disponíveis para Android, iOS, Web e Flutter.

material.io/develop

No codelab MDC-101, você usou dois componentes do Material Design (MDC) para criar uma página de login: campos de texto e botões. Agora, vamos nos aprofundar nessa base adicionando navegação, estrutura e dados.

O que você criará

Neste codelab, você criará uma tela inicial para o app Shrine, um app de comércio eletrônico que vende roupas e artigos domésticos. Ele conterá:

  • Uma barra de apps superior.
  • Uma lista de produtos em grade

Componentes do MDC-Android neste codelab

  • AppBarLayout
  • MaterialCardView

O que é necessário

  • Conhecimento básico de desenvolvimento para Android.
  • Android Studio (faça o download dele aqui, caso ainda não tenha feito)
  • Um dispositivo ou emulador Android (disponível no Android Studio)
  • O exemplo de código (veja a próxima etapa)

Como você classificaria seu nível de experiência na criação de apps Android?

Iniciante Intermediário Proficiente

Está continuando do MDC-101?

Se você concluiu o MDC-101, o código para este codelab já está pronto. Pule para a etapa 3: Adicionar uma barra de apps superior.

Está começando do zero?

Faça o download do app inicial do codelab

Fazer o download do app inicial

O app inicial está localizado no diretório material-components-android-codelabs-102-starter/java. cd antes do início.

... ou clone-o do GitHub

Para clonar este codelab do GitHub, execute estes comandos:

git clone https://github.com/material-components/material-components-android-codelabs
cd material-components-android-codelabs/
git checkout 102-starter

Carregar o código inicial no Android Studio

  1. Quando o assistente de configuração for concluído e a janela Welcome to Android Studio for exibida, clique em Open an existing Android Studio project. Acesse o diretório em que você instalou o exemplo de código e selecione java -> Shrine (ou pesquise shine no computador para abrir o projeto Shrine.
  2. Aguarde um pouco enquanto o Android Studio cria e sincroniza o projeto, conforme mostrado nos indicadores de atividade na parte inferior da janela.
  3. Como o SDK do Android ou as ferramentas de compilação não estão presentes, o Android Studio poderá encontrar alguns erros de compilação. Veja um exemplo a seguir. Siga as instruções no Android Studio para instalar/atualizar essas ferramentas e sincronizar o projeto.

Adicionar dependências do projeto

O projeto precisa de uma dependência na Biblioteca de Suporte Android MDC. O exemplo de código transferido por download já precisa ter essa dependência listada, mas recomendamos seguir as etapas abaixo para garantir isso.

  1. Navegue até o arquivo build.gradle do módulo app e confira se o bloco dependencies inclui uma dependência no MDC Android:
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (Opcional) Se necessário, edite o arquivo build.gradle para adicionar as seguintes dependências e sincronizar o projeto.
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'
}

Executar o app inicial

  1. Confira se a configuração do build à esquerda do botão Run / Play é app.
  2. Pressione o botão verde Run / Play para criar e executar o app.
  3. Na janela Select Deployment Target, se você já tiver um dispositivo Android listado nos seus dispositivos disponíveis, pule para a Etapa 8. Caso contrário, clique em Create New Virtual Device.
  4. Na tela Select Hardware, selecione um smartphone, como o Pixel 2, e clique em Next.
  5. Na tela System Image, selecione uma versão recente do Android, de preferência o nível da API mais alto. Se ele não estiver instalado, clique no link Download exibido e faça o download.
  6. Clique em Próxima.
  7. Na tela Android Virtual Device (AVD), mantenha as configurações como estão e clique em Finish.
  8. Selecione um dispositivo Android na caixa de diálogo de destino da implantação.
  9. Clique em OK.
  10. O Android Studio cria o app, faz a implantação e o abre automaticamente no dispositivo de destino.

Pronto. Você verá a página de login do Shrine do codelab MDC-101.

Agora que a tela de login está pronta, vamos preencher o app com alguns produtos.

A tela inicial é revelada quando a página de login é dispensada, com uma tela mostrando "quot;Você conseguiu!". Isso é ótimo. Mas agora o usuário não pode realizar nenhuma outra ação e também não sabe em que parte do app está. Vamos adicionar navegação para ajudar você com isso.

O Material Design oferece padrões de navegação que garantem uma boa usabilidade. Um dos componentes de navegação mais importantes é a barra de apps superior.

Para que os usuários possam navegar e ter acesso rápido a outras ações, vamos adicionar uma barra de apps superior.

Adicionar um widget AppBar

No arquivo shr_product_grid_fragment.xml, exclua a tag <LinearLayout> que contém o texto ""Você conseguiu!" TextView e substitua pelo seguinte:

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>

O shr_product_grid_fragment.xml será semelhante a este:

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>

Muitas barras de apps têm um botão ao lado do título. Vamos adicionar um ícone de menu ao nosso.

Adicionar um ícone de navegação

Ainda no shr_product_grid_fragment.xml, adicione o seguinte ao componente XML Toolbar (que você acabou de adicionar ao layout):

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

O shr_product_grid_fragment.xml será semelhante a este:

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>

Adicionar botões de ação e definir o estilo da barra de apps superior

Também é possível adicionar botões ao lado final da barra de apps. No Android, eles são chamados de botões de ação.

Vamos personalizar a barra de apps superior e adicionar botões de ação ao menu dela de forma programática.

Primeiro, vamos criar um método para configurar a barra de ferramentas. O método precisa conseguir uma referência à barra de ferramentas usando o id, além de fazer referência à atividade usando getActivity(). Se a atividade não for nula, defina o Toolbar para ser usado como um ActionBar usando setSupportActionBar:

ProductGridFragment.java (em inglês)

private void setUpToolbar(View view) {
   Toolbar toolbar = view.findViewById(R.id.app_bar);
   AppCompatActivity activity = (AppCompatActivity) getActivity();
   if (activity != null) {
       activity.setSupportActionBar(toolbar);
   }
}

Em seguida, logo abaixo do método setUpToolbar que acabamos de adicionar, vamos substituir o onCreateOptionsMenu para inflar o conteúdo do shr_toolbar_menu.xml na barra de ferramentas:

ProductGridFragment.java (em inglês)

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
   menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
   super.onCreateOptionsMenu(menu, menuInflater);
}

Agora, adicione uma chamada ao método setUpToolbar que adicionamos ao conteúdo do método onCreateView() com o seguinte:

ProductGridFragment.java (em inglês)

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   // Inflate the layout for this fragment with the ProductGrid theme
   View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

   // Set up the toolbar
   setUpToolbar(view);

   return view;
}

Por fim, adicione um método onCreate() à ProductGridFragment.java. No corpo do método, defina o parâmetro de setHasOptionMenu como true.

O método será assim:

ProductGridFragment.java (em inglês)

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setHasOptionsMenu(true);
}

O código acima define a barra de apps do nosso layout XML como a barra de ações da atividade. O callback onCreateOptionsMenu informa à atividade o que usar como menu. Nesse caso, os itens de menu do R.menu.shr_toolbar_menu serão colocados na barra de apps.

O arquivo de menu contém dois itens: "Pesquisa" e "Filtro".

shr_Toolbar_menu.xml (link em inglês)

<?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>

Depois dessas mudanças, seu arquivo ProductGridFragment.java ficará assim:

ProductGridFragment.java (em inglês)

package com.google.codelabs.mdc.java.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 android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;


public class ProductGridFragment extends Fragment {

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }
  
   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

       // Set up the toolbar
       setUpToolbar(view);

       return view;
   }
  
   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }

   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
       super.onCreateOptionsMenu(menu, menuInflater);
   }

}

Crie e execute. A tela inicial ficará assim:

Agora a barra de ferramentas tem um ícone de navegação, um título e dois ícones de ação no lado direito. A barra de ferramentas também exibe a elevação usando uma sombra sutil, que os mostra em uma camada diferente da do conteúdo.

Agora que nosso app tem uma estrutura básica, vamos organizar o conteúdo colocando-o em cards.

Adicionar um cartão

Para começar, vamos adicionar um card abaixo da barra de apps superior. O cartão precisa ter a região de uma imagem, um título e um rótulo para texto secundário.

Em shr_product_grid_fragment.xml , adicione o código a seguir a 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>

Criar e executar:

Nesta visualização, é possível ver que o card se enquadra na borda esquerda da tela e tem cantos arredondados e uma sombra (que representa a elevação dele). Toda a área é chamada de "container." Com exceção do próprio contêiner, todos os elementos dentro dele são opcionais.

Você pode adicionar os seguintes elementos a um contêiner: texto do cabeçalho, miniatura ou avatar, subtítulo, divisores e até mesmo botões e ícones. O card que criamos, por exemplo, contém dois TextViews (um para o título e um para o texto secundário) em um LinearLayout, alinhado à parte inferior do card.

Os cards geralmente são exibidos com outros em uma coleção. Na próxima seção deste codelab, eles serão dispostos em uma grade.

Quando há vários cards em uma tela, eles são agrupados em uma ou mais coleções. Os cards em uma grade são coplanares, o que significa que eles compartilham a mesma elevação de repouso (a menos que sejam extraídos ou arrastados, mas isso não será abordado neste codelab).

Configurar a grade de cards

Confira o arquivo shr_product_card.xml que fornecemos:

shr_product_card.xml (link em inglês)

<?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>

O layout desse card contém um card com uma imagem (aqui, um NetworkImageView, que permite incluir imagens de um URL), e dois TextViews.

Depois, confira o ProductCardRecyclerViewAdapter que fornecemos para você. Está no mesmo pacote que ProductGridFragment.

ProductCardRecyclerViewAdapter.java (link em inglês)

package com.google.codelabs.mdc.java.shrine;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.google.codelabs.mdc.java.shrine.network.ImageRequester;
import com.google.codelabs.mdc.java.shrine.network.ProductEntry;

import java.util.List;

/**
* Adapter used to show a simple grid of products.
*/
public class ProductCardRecyclerViewAdapter extends RecyclerView.Adapter<ProductCardViewHolder> {

   private List<ProductEntry> productList;
   private ImageRequester imageRequester;

   ProductCardRecyclerViewAdapter(List<ProductEntry> productList) {
       this.productList = productList;
       imageRequester = ImageRequester.getInstance();
   }

   @NonNull
   @Override
   public ProductCardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
       View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.shr_product_card, parent, false);
       return new ProductCardViewHolder(layoutView);
   }

   @Override
   public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
       // TODO: Put ViewHolder binding code here in MDC-102
   }

   @Override
   public int getItemCount() {
       return productList.size();
   }
}

A classe de adaptador acima gerencia o conteúdo da nossa grade. Para determinar o que cada visualização deve fazer com o conteúdo fornecido, em breve criaremos o código para onBindViewHolder().

No mesmo pacote, também é possível analisar ProductCardViewHolder. Essa classe armazena as visualizações que afetam o layout do card. Assim, poderemos modificá-las mais tarde.

ProductCardViewHolder.java

package com.google.codelabs.mdc.java.shrine;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;

public class ProductCardViewHolder extends RecyclerView.ViewHolder {

   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       // TODO: Find and store views from itemView
   }
}

Para configurar nossa grade, primeiro precisamos remover o marcador MaterialCardView de shr_product_grid_fragment.xml. Em seguida, adicione o componente que representa nossa grade de cards. Nesse caso, adicione um componente RecyclerView ao shr_product_grid_fragment.xml abaixo do 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>

O shr_product_grid_fragment.xml será semelhante a este:

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 fim, no onCreateView(), adicione o código de inicialização RecyclerView ao ProductGridFragment.java depois de chamar setUpToolbar(view) e antes da instrução return:

ProductGridFragment.java (em inglês)

@Override
public View onCreateView(
       @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
   ...
   setUpToolbar(view);

   // Set up the RecyclerView
   RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
   recyclerView.setHasFixedSize(true);
   recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
   ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
           ProductEntry.initProductEntryList(getResources()));
   recyclerView.setAdapter(adapter);
   int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
   int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
   recyclerView.addItemDecoration(new ProductGridItemDecoration(largePadding, smallPadding));

   return view;
}

O snippet de código acima contém as etapas de inicialização necessárias para configurar uma RecyclerView. Isso inclui a configuração do gerenciador de layout do RecyclerView, mais a inicialização e a definição do adaptador do RecyclerView.

Seu arquivo ProductGridFragment.java ficará assim:

ProductGridFragment.java (em inglês)

package com.google.codelabs.mdc.java.shrine;

import android.os.Bundle;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;


import com.google.codelabs.mdc.java.shrine.network.ProductEntry;

public class ProductGridFragment extends Fragment {

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setHasOptionsMenu(true);
   }

   @Override
   public View onCreateView(
           @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       // Inflate the layout for this fragment with the ProductGrid theme
       View view = inflater.inflate(R.layout.shr_product_grid_fragment, container, false);

       // Set up the toolbar
       setUpToolbar(view);

       // Set up the RecyclerView
       RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
       recyclerView.setHasFixedSize(true);
       recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2, GridLayoutManager.VERTICAL, false));
       ProductCardRecyclerViewAdapter adapter = new ProductCardRecyclerViewAdapter(
               ProductEntry.initProductEntryList(getResources()));
       recyclerView.setAdapter(adapter);
       int largePadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing);
       int smallPadding = getResources().getDimensionPixelSize(R.dimen.shr_product_grid_spacing_small);
       recyclerView.addItemDecoration(new ProductGridItemDecoration(largePadding, smallPadding));

       return view;
   }

   private void setUpToolbar(View view) {
       Toolbar toolbar = view.findViewById(R.id.app_bar);
       AppCompatActivity activity = (AppCompatActivity) getActivity();
       if (activity != null) {
           activity.setSupportActionBar(toolbar);
       }
   }

   @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
       menuInflater.inflate(R.menu.shr_toolbar_menu, menu);
       super.onCreateOptionsMenu(menu, menuInflater);
   }

}

Crie e execute.

Os cards já estão disponíveis. Ainda não há nada. Por isso, vamos adicionar alguns dados do produto.

Adicionar imagens e textos

Para cada card, adicione uma imagem, um nome do produto e um preço. A abstração ViewHolder contém as visualizações de cada card. Em ViewHolder, adicione as três visualizações da seguinte forma:

ProductCardViewHolder.java

package com.google.codelabs.mdc.java.shrine;

import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;

import com.android.volley.toolbox.NetworkImageView;

public class ProductCardViewHolder extends RecyclerView.ViewHolder {

   public NetworkImageView productImage;
   public TextView productTitle;
   public TextView productPrice;

   public ProductCardViewHolder(@NonNull View itemView) {
       super(itemView);
       productImage = itemView.findViewById(R.id.product_image);
       productTitle = itemView.findViewById(R.id.product_title);
       productPrice = itemView.findViewById(R.id.product_price);
   }
}

No adaptador RecyclerView de ViewHolder,, atualize o método onBindViewHolder() para definir as informações em cada visualização:

ProductCardRecyclerViewAdapter.java (link em inglês)

@Override
public void onBindViewHolder(@NonNull ProductCardViewHolder holder, int position) {
   if (productList != null && position < productList.size()) {
       ProductEntry product = productList.get(position);
       holder.productTitle.setText(product.title);
       holder.productPrice.setText(product.price);
       imageRequester.setImageFromUrl(holder.productImage, product.url);
   }
}

O código acima informa ao adaptador RecyclerView o que fazer com cada card, usando um ViewHolder.

Aqui, ele define os dados de texto em cada um dos TextViews do ViewHolder e chama um ImageRequester para receber uma imagem de um URL. A ImageRequester é uma classe fornecida por sua conveniência e usa a biblioteca Volley (esse é um tópico fora do escopo deste codelab, mas fique à vontade para explorar o código por conta própria).

Criar e executar:

Agora, nossos produtos estão sendo exibidos no app.

Nosso app tem um fluxo básico que leva o usuário da tela de login a uma tela inicial, onde os produtos são exibidos. Em apenas algumas linhas de código, adicionamos uma barra de apps superior com um título e três botões, além de uma grade de cards para apresentar o conteúdo do nosso app. Nossa tela inicial agora é simples e funcional, com uma estrutura básica e um conteúdo acionável.

Próximas etapas

Agora, com a barra de apps superior, o card, o campo de texto e o botão, usamos quatro componentes principais do Material Design na biblioteca MDC-Android. Conheça ainda mais componentes nos componentes do MDC-Android Catalog no MDC para Android.

Embora seja totalmente funcional, nosso app ainda não expressa uma marca específica. No codelab MDC-103: temas do Material Design usando cor, forma, elevação e tipo, vamos personalizar o estilo desses componentes para representar uma marca vibrante e moderna.

Este codelab exigiu esforço e tempo normais para ser concluído

Concordo totalmente Concordo Não concordo nem discordo Discordo Discordo totalmente

Quero continuar usando componentes do Material Design no futuro

Concordo totalmente Concordo Não concordo nem discordo Discordo Discordo totalmente