MDC-101 Android: マテリアル コンポーネント(MDC)基本(Java)

logo_components_color_2x_web_96dp.png

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

material.io/develop

Android のマテリアル デザインとマテリアル コンポーネントについて

マテリアル デザインは、人の目に留まる美しいデジタル プロダクトを作成するためのシステムです。一貫した一連の基本原則とコンポーネントに基づいてスタイル、ブランディング、インタラクション、モーションの統一を行うことにより、プロダクト チームは、デザインの可能性を最大限に発揮できます。

Android アプリの場合は、Android 用マテリアル コンポーネントMDC Android)が設計とエンジニアリングをコンポーネント ライブラリと組み合わせ、アプリ間で一貫性を実現します。マテリアル デザイン システムが進化するにつれ、これらのコンポーネントは、ピクセル パーフェクトな実装を保ち、Google のフロントエンド開発標準に準拠するように更新されます。MDC は、ウェブ、iOS、Flutter でも使用できます。

この Codelab では、MDC Android コンポーネントをいくつか使用して、ログインページを作成します。

作成するアプリの概要

この Codelab は、衣類と生活雑貨を販売する e コマース Android アプリ Shrine の作成手順を説明する 4 つの Codelab のうちの最初の Codelab です。MDC-Android を使用して、ブランドやスタイルを反映するようにコンポーネントをカスタマイズする方法を紹介します。

この Codelab では、次のもの含む Shrine 用ログインページを作成します。

  • テキスト フィールド 2 つ(ユーザー名用とパスワード用)
  • 2 つのボタン(「キャンセル」用と「次へ」用)
  • アプリ名「Shrine」
  • Shrine のロゴ画像

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

  • テキスト フィールド
  • ボタン

必要なもの

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

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

初心者 中級者 上級者

Android Studio を起動する

Android Studio を開くと、「Welcome to Android Studio」というタイトルのウィンドウが表示されます。ただし、Android Studio を初めて起動している場合は、Android Studio 設定ウィザードの各手順を、デフォルト値を設定しながら進めていきます。このステップでは、必要なファイルのダウンロードとインストールに数分間かかる場合があります。バックグラウンドで実行させたまま、次のセクションに取り組んでもかまいません。

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

スターター アプリをダウンロード

スターター アプリは material-components-android-codelabs-101-starter/java ディレクトリにあります。

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

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

git clone https://github.com/material-components/material-components-android-codelabs
cd material-components-android-codelabs/
git checkout 101-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 の指示に従って、それをインストール/更新して、プロジェクトを同期してください。

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

プロジェクトに 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. [Run / Play] ボタンの左側にあるビルド構成が 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 によってアプリがビルドおよびデプロイされ、対象デバイスでそのアプリが自動的に開きます。

完了しました。Shrine のログインページのスターター コードはエミュレータで動作しているはずです。「Shrine」という名前と、その真下に Shrine のロゴが表示されます。

次に、コードを見てみましょう。フラグメントを表示し、フラグメント間を移動するためのシンプルな Fragment ナビゲーション フレームワークをサンプルコードに用意しました。

shrine -> app -> src -> main -> java -> com.google.codelabs.mdc.java.shrine ディレクトリにある MainActivity.java を開きます。以下が含まれているはずです。

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

このアクティビティは、shr_main_activity.xml で定義された R.layout.shr_main_activity レイアウト ファイルを表示します。

onCreate(), で、MainActivity.javaLoginFragment を表示するために Fragment トランザクションを開始していることがわかります。LoginFragment. この Codelab ではこれを変更します。また、アクティビティでは、NavigationHost で定義された navigateTo(Fragment) メソッドが実装されており、任意のフラグメントを別のフラグメントに移動できます。

アクティビティ ファイルでcommand キーを押しながらクリック(または Ctrl キーを押しながらクリックshr_main_activity すると、レイアウト ファイルが開きます。または、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" />

ここでは、アクティビティが表示するフラグメントのコンテナとして機能する単純な <FrameLayout> を示しています。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
}

LoginFragmentshr_login_fragment レイアウト ファイルをインフレートし、onCreateView() に表示します。shr_login_fragment.xml レイアウト ファイルを確認して、ログインページの内容を見てみましょう。

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>

この例では、<LinearLayout> の上に <ImageView> が表示されています。これは「Shrine」ロゴを表しています。

その後に、「SHRINE」ラベルを表す <TextView> タグがあります。このラベルのテキストは、@string/shr_app_name という名前の文字列リソースです。command + クリック(または Ctrl + クリック)して文字列リソース名を指定するか、app -> res -> values -> strings.xml を開くと、文字列リソースが定義されている strings.xml ファイルが表示されます。後でさらに文字列リソースが追加されると、ここで定義されます。このファイル内のすべてのリソースには、Shrine アプリの一部であることを示す shr_ 接頭辞を付ける必要があります。

スターター コードに慣れてきたところで、最初のコンポーネントを実装しましょう。

まず、ユーザーがユーザー名とパスワードを入力できるように、ログインページに 2 つのテキスト フィールドを追加します。MDC テキスト フィールド コンポーネントを使用します。これには、フローティング ラベルやエラー メッセージを表示する機能が組み込まれています。

XML を追加する

shr_login_fragment.xml で、<LinearLayout> 内の「TextInputEditText」と「<TextView>」の下に子 TextInputEditText を持つ 2 つの TextInputLayout 要素を追加します。

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>

上記のスニペットは、2 つのテキスト フィールドを表します。各フィールドは、<TextInputLayout> 要素と <TextInputEditText> 子で構成されます。各テキスト フィールドのヒントテキストは、android:hint 属性で指定します。

テキスト フィールド用に、@string/shr_hint_username@string/shr_hint_password という 2 つの新しい文字列リソースを追加しました。strings.xml を開いて、これらの文字列リソースを表示します。

strings.xml

...
<string name="shr_hint_username">Username</string>
<string name="shr_hint_password">Password</string>
...

入力検証を追加する

TextInputLayout コンポーネントには、組み込みのエラー フィードバック機能があります。

エラー フィードバックを表示するには、shr_login_fragment.xml に次の変更を加えます。

  • パスワード TextInputLayout 要素で app:errorEnabled 属性を true に設定します。これにより、テキスト フィールドの下にエラー メッセージのパディングが追加されます。
  • Password TextInputEditText 要素で android:inputType 属性を「textPassword」に設定します。パスワード欄の入力テキストを非表示にします。

これらの変更を行うと、shr_login_fragment.xml のテキスト フィールドは次のようになります。

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>

アプリを実行してみましょう。「Username」と「Password」という 2 つのテキスト フィールドを備えたページが表示されます。

フローティング ラベルのアニメーションを確認します。

次に、ログインページに「Cancel」と「Next」という 2 つのボタンを追加します。MDC ボタン コンポーネントを使用します。このコンポーネントには、象徴的なマテリアル デザインのインクリップル効果が組み込まれています。

XML を追加する

shr_login_fragment.xml で、TextInputLayout 要素の下の <LinearLayout><RelativeLayout> を追加します。次に、<RelativeLayout> に 2 つの <MaterialButton> 要素を追加します。

結果の XML ファイルは次のようになります。

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>

これで、アプリを実行すると、各ボタンをタップするとインクの波紋が表示されます。

最後に、LoginFragment.java に Java コードを追加して、[NEXT] ボタンを別のフラグメントに接続します。レイアウトに追加した各コンポーネントに id が割り当てられています。これらの id を使用してコード内のコンポーネントを参照し、エラーのチェックとナビゲーションを行います。

LoginFragment.java に、onCreateView() の下にある非公開のブール値 isPasswordValid メソッドを追加し、パスワードが有効かどうかを判断するロジックを追加します。このデモでは、パスワードが 8 文字以上であることを確認します。

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

次に、「次へ」ボタンにクリック リスナーを追加します。このボタンは、先ほど作成した isPasswordValid() メソッドに基づいてエラーを設定してクリアします。onCreateView() では、このクリック リスナーはインフレータ ラインと return view ラインの間に配置する必要があります。

次に、キー リスナーをパスワード TextInputEditText に追加して、エラーをクリアするキーイベントをリッスンします。このリスナーでは、isPasswordValid() を使用してパスワードが有効かどうかを確認する必要もあります。これは、onCreateView() のクリック リスナーの直下に追加できます。

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

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

これで、別のフラグメントに移動できるようになりました。エラー検証が成功した場合、onCreateView()OnClickListener を更新して別のフラグメントに移動する。次の行を追加して、クリック リスナーの else ケースに ProductGridFragment で移動します。

LoginFragment.java

...
((NavigationHost) getActivity()).navigateTo(new ProductGridFragment(), false); // Navigate to the next Fragment
...

クリック リスナーは次のようになります。

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

この新しいコード行は、MainActivity から navigateTo() メソッドを呼び出して新しいフラグメント(ProductGridFragment)に移動します。現時点では、MDC-102 で作業する空のページです。

アプリをビルドしたら、[次へ] ボタンを押してください。

これで完了です。この画面は、MDC-102 で取り組む次の Codelab の出発点となります。

マテリアル XML は、基本的な XML マークアップと 30 行以内の Java を使用して、マテリアル デザイン ガイドラインを遵守した美しいログインページを作成します。また、すべてのデバイスで一貫した外観と動作を実現します。

次のステップ

テキスト フィールドとボタンは、MDC Android ライブラリの 2 つのコア コンポーネントですが、他にも多数あります。残りの MDC Android のコンポーネントをご確認ください。または、MDC 102: マテリアル デザインの構造とレイアウトにアクセスして、トップ アプリバー、カードビュー、グリッド レイアウトについて学習する。マテリアル コンポーネントをお試しいただきありがとうございます。この Codelab がお役に立ちましたら幸いです。

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

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

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

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