MDC-102 Android: マテリアルの構造とレイアウト(Java)

1. はじめに

logo_components_color_2x_web_96dp.png

マテリアル コンポーネント(MDC)は、デベロッパーがマテリアル デザインを実装する際に役立ちます。Google のエンジニアと UX デザイナーのチームが作成した MDC には、美しく機能的な UI コンポーネントが多数含まれており、Android、iOS、ウェブ、Flutter.material.io/develop に利用可能です。

Codelab MDC-101 では、2 つのマテリアル コンポーネント(MDC)(テキスト フィールドとボタン)を使用してログインページを作成しました。今度は、この基礎にナビゲーション、構造、データを追加していきましょう。

作成するアプリの概要

この Codelab では、衣類と生活雑貨を販売する e コマースアプリ Shrine のホーム画面を作成します。これには次のものが含まれます。

  • トップ アプリバー
  • 商品のグリッドリスト

249db074eff043f4.png

この Codelab の MDC-Android コンポーネント

  • AppBarLayout
  • MaterialCardView

必要なもの

  • Android 開発に関する基本的な知識
  • Android Studio(まだお持ちでない場合はこちらからダウンロードしてください)
  • Android Emulator または Android デバイス(Android Studio から入手可能)
  • サンプルコード(次の手順を参照)

Android アプリ作成経験についてお答えください。

初心者 中級者 上級者

2. 開発環境を設定する

MDC-101 から続行する場合

MDC-101 を完了していれば、コードはこの Codelab 用に準備されています。ステップ 3(トップ アプリバーを追加する)に進みます。

ゼロから始める

Codelab のスターター アプリをダウンロードする

スターター アプリは material-components-android-codelabs-102-starter/java ディレクトリにあります。開始する前に、そのディレクトリへの cd を行ってください。

GitHub からクローンを作成する

GitHub からこの Codelab のクローンを作成するには、次のコマンドを実行します。

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

Android Studio にスターター コードを読み込む

  1. 設定ウィザードが完了し、[Welcome to Android Studio] ウィンドウが表示されたら、[Open an existing Android Studio project] をクリックします。サンプルコードをインストールしたディレクトリに移動し、java -> Shrine を選択(またはパソコンで「shrine」を検索)して、Shrine プロジェクトを開きます。
  2. Android Studio がプロジェクトをビルドして同期するまで待ちます。進捗状況は、Android Studio ウィンドウ下部のアクティビティ インジケーターに表示されます。
  3. この時点では、Android SDK やビルドツール(以下に示すものなど)が不足しているため、Android Studio でビルドエラーが発生する場合があります。Android Studio の指示に従って、それをインストール / 更新して、プロジェクトを同期させます。

F5H6srsw_5xOPGFpKrm1RwgewatxA_HUbDI1PWoQUAoJcT6DpfBOkAYwq3S-2vUHvweUaFgAmG7BtUKkGouUbhTwXQh53qec8tO5eVecdlo7QIoLc8rNxFEBb8l7RlS-KzBbZOzVhA

プロジェクトの依存関係を追加する

プロジェクトに MDC Android サポート ライブラリへの依存関係が必要である。ダウンロードしたサンプルコードには、すでにこの依存関係がリストされているはずですが、次の手順で確認することをおすすめします。

  1. app モジュールの build.gradle ファイルに移動し、dependencies ブロックに MDC Android への依存関係が含まれていることを確認します。
api 'com.google.android.material:material:1.1.0-alpha06'
  1. (省略可)必要に応じて build.gradle ファイルを編集して次の依存関係を追加し、プロジェクトを同期します。
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'
}

スターター アプリを実行する

  1. [実行 / 再生ボタン] の左側にあるビルド構成が app であることを確認します。
  2. 緑色の [Run / Play] ボタンを押して、アプリをビルドし実行します。
  3. [Select Deployment Target] ウィンドウで、利用可能なデバイスの一覧にすでに Android デバイスが表示されている場合は、ステップ 8 に進みます。それ以外の場合は、[Create New Virtual Device] をクリックします。
  4. [Select Hardware] 画面で [Pixel 2] などのスマートフォン デバイスを選択し、[Next] をクリックします。
  5. [System Image] 画面で、最新の Android バージョン(可能であれば API レベルが最も高いもの)を選択します。インストールされていない場合は、表示される [Download] をクリックして、ダウンロードを完了します。
  6. [Next] をクリックします。
  7. [Android Virtual Device (AVD)] 画面で、設定をそのまま変更せずに、[Finish] をクリックします。
  8. デプロイ ターゲット ダイアログから Android デバイスを選択します。
  9. [OK] をクリックします。
  10. Android Studio によってアプリがビルドおよびデプロイされ、対象デバイスでそのアプリが自動的に開きます。

完了しました。MDC-101 Codelab で作成した Shrine のログインページが表示されます。

4cb0c218948144b4.png

ログイン画面が正常に表示されるようになったので、アプリにいくつかのプロダクトを追加しましょう。

3. トップ アプリバーを追加する

ログインページを閉じるとホーム画面が表示され、「完了」というメッセージが画面に表示されます。ここまでは問題ないのですが、今のところユーザーは何もできず、アプリ内のどこにいるのかわからない状態です。そこで、ナビゲーションを追加します。

マテリアル デザインには、高度なユーザビリティを実現するナビゲーション パターンがあります。特に目立つナビゲーション コンポーネントの 1 つが、トップ アプリバーです。

ナビゲーションを提供し、ユーザーが他のアクションにすばやくアクセスできるように、トップ アプリバーを追加しましょう。

AppBar ウィジェットを追加する

shr_product_grid_fragment.xml で、「完了」を含む <LinearLayout> タグを削除します。TextView に置き換え、次のように置き換えます。

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>

shr_product_grid_fragment.xml は次のようになります。

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>

アプリバーは多くの場合、タイトルの横にボタンがあります。メニュー アイコンを追加しましょう。

ナビゲーション アイコンを追加する

引き続き shr_product_grid_fragment.xml で、(レイアウトに追加したばかりの)Toolbar XML コンポーネントに以下を追加します。

shr_product_grid_fragment.xml

app:navigationIcon="@drawable/shr_menu"

shr_product_grid_fragment.xml は次のようになります。

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>

アクション ボタンを追加して上部のアプリバーのスタイルを設定する

アプリバーの端にボタンを追加することもできます。Android では、これらは操作ボタンと呼ばれます。

トップ アプリバーのスタイルを設定し、プログラムでそのメニューにアクション ボタンを追加します。

まず、ツールバーを設定するメソッドを作成します。このメソッドは、id を使用してツールバーへの参照を取得し、getActivity() を使用してアクティビティへの参照も取得する必要があります。アクティビティが null でない場合、setSupportActionBar を使用して ActionBar として使用される Toolbar を設定します。

ProductGridFragment.java

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

次に、先ほど追加した setUpToolbar メソッドの直下で、onCreateOptionsMenu をオーバーライドして、shr_toolbar_menu.xml のコンテンツをツールバーにインフレートします。

ProductGridFragment.java

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

次に、onCreateView() メソッドの内容に追加した setUpToolbar メソッドの呼び出しを、次のように追加します。

ProductGridFragment.java

@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;
}

最後に、ProductGridFragment.javaonCreate() メソッドを追加します。メソッド本体で、setHasOptionMenu のパラメータを true に設定します。

メソッドは次のようになります。

ProductGridFragment.java

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

上記のコードでは、XML レイアウトのアプリバーをこのアクティビティのアクションバーとして設定しています。コールバック onCreateOptionsMenu は、メニューとして何を使用するかをアクティビティに指示します。この例では、R.menu.shr_toolbar_menu のメニュー項目がアプリバーに配置されます。

メニュー ファイルには、「検索」と「フィルタ」の 2 つの項目が含まれています。

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>

変更後、ProductGridFragment.java ファイルは次のようになります。

ProductGridFragment.java

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);
   }

}

ビルドして実行します。ホーム画面は次のようになります。

d04e8aa3b27f4754.png

ツールバーにナビゲーション アイコンとタイトルが配置され、右側に 2 つのアクション アイコンが表示されるようになりました。また、ツールバーでは、微妙な影を使って高度が表示され、コンテンツとは異なるレイヤにあることがわかります。

4. カードを追加する

アプリの構造がある程度できたので、コンテンツをカードに入れて整理しましょう。

カードを追加する

まずは、トップ アプリバーの下にカードを 1 つ追加しましょう。カードには、画像用の領域、タイトル、付随するテキストのラベルが必要です。

shr_product_grid_fragment.xml で、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>

ビルドして実行します。

f6184a55ccb5f920.png

このプレビューでは、カードが画面の左端からインセットされており、角が丸く、影(カードの高度を表現)になっています。この領域全体が「コンテナ」と呼ばれます。コンテナ自体を除き、コンテナ内の要素はすべて省略可能です。

コンテナには、ヘッダー テキスト、サムネイルまたはアバター、小見出し、分割線、さらにはボタンやアイコンといった要素を追加できます。たとえば、作成したカードには、LinearLayout 内に 2 つの TextView(タイトル用とセカンダリ テキスト用)が含まれ、カードの下部に配置されています。

カードは通常、他のカードと一緒にコレクションで表示されます。この Codelab の次のセクションでは、それらをコレクションとしてグリッドに配置します。

5. カードのグリッドを作成する

複数のカードが画面に表示されている場合は、1 つ以上のコレクションにグループ化されます。グリッド内のカードは同一平面上にあるため、互いに同じ静止高度を共有します(カードを選択またはドラッグしない限り、この Codelab では扱いません)。

カードのグリッドを設定する

用意されている shr_product_card.xml ファイルを見てみましょう。

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>

このカード レイアウトには、画像を含むカード(ここでは URL の画像を含めることができる NetworkImageView)と 2 つの TextViews が含まれています。

次に、提供されている ProductCardRecyclerViewAdapter を確認します。ProductGridFragment と同じパッケージにあります。

ProductCardRecyclerViewAdapter.java

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();
   }
}

上記のアダプタクラスは、グリッドのコンテンツを管理します。各ビューが特定のコンテンツに対して行うべき処理を決定するため、次に onBindViewHolder() のコードを書きます。

同じパッケージで ProductCardViewHolder を見ることもできます。このクラスには、カードのレイアウトに影響するビューが保存されるため、後で変更できます。

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

グリッドを設定するには、まず shr_product_grid_fragment.xml からプレースホルダ MaterialCardView を削除します。次に、カードのグリッドを表すコンポーネントを追加します。この場合、RecyclerView コンポーネントを、AppBarLayout XML コンポーネントの下の shr_product_grid_fragment.xml に追加します。

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>

shr_product_grid_fragment.xml は次のようになります。

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>

最後に、onCreateView() で、setUpToolbar(view) を呼び出した後で return ステートメントの前に、ProductGridFragment.javaRecyclerView 初期化コードを追加します。

ProductGridFragment.java

@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;
}

上記のコード スニペットには、RecyclerView を設定するために必要な初期化ステップが含まれています。これには、RecyclerView のレイアウト マネージャーの設定、RecyclerView のアダプターの初期化と設定が含まれます。

ProductGridFragment.java ファイルは次のようになります。

ProductGridFragment.java

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);
   }

}

ビルドして実行します。

f9aeab846fc3bb4c.png

カードが手に入りました。まだ何も表示されていないので、商品データを追加しましょう。

画像とテキストを追加する

カードごとに、画像、商品名、価格を追加します。ViewHolder 抽象化は各カードのビューを保持します。ViewHolder で、次のように 3 つのビューを追加します。

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);
   }
}

RecyclerView のアダプターで、ViewHolder,onBindViewHolder() メソッドを更新して各ビューの情報を設定します。

ProductCardRecyclerViewAdapter.java

@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);
   }
}

上記のコードは、ViewHolder を使用して、各カードに対して RecyclerView のアダプタに何をすべきかを指示します。

ここでは、各 ViewHolderTextView にテキスト データを設定し、ImageRequester を呼び出して URL から画像を取得します。ImageRequester は便宜上用意したクラスで、Volley ライブラリを使用します(このトピックは Codelab の範囲外ですが、コードを自由に調べてください)。

ビルドして実行します。

249db074eff043f4.png

これで、商品がアプリに表示されるようになりました。

6. まとめ

アプリに、ログイン画面からホーム画面に移動して商品を表示する基本的なフローができました。わずか数行のコードで、タイトルと 3 つのボタンを含むトップ アプリバーと、アプリのコンテンツを表示するカードのグリッドを追加しました。ホーム画面は、基本的な構造と実用的なコンテンツを備えた、シンプルかつ機能的なものになりました。

次のステップ

トップ アプリバー、カード、テキスト フィールド、ボタンにより、MDC-Android ライブラリの 4 つのコア マテリアル デザイン コンポーネントを使用しました。その他のコンポーネントについては、MDC-Android カタログの MDC Android のコンポーネントをご覧ください。

アプリは完全に機能しますが、特定のブランドはまだ表現されていません。MDC-103: 色、形状、高度、タイプによるマテリアル デザインのテーマ設定では、これらのコンポーネントのスタイルをカスタマイズして、鮮やかでモダンなブランドを表現します。

この Codelab を完了するためにそれなりの時間と労力を必要とした

非常にそう思う そう思う どちらとも言えない そう思わない まったくそう思わない

今後もマテリアル コンポーネントを使用したい

非常にそう思う そう思う どちらとも言えない そう思わない まったくそう思わない