MaterialComponentsを使ったお手軽マテリアルデザイン

[TECOTEC Advent Calendar 2019](https://qiita.com/advent-calendar/2019/tecotec)の３年連続で１９日目担当の柴犬です。

突然ですが皆さん、マテリアルデザイン使ってますか？
マテリアルデザインって何ぞや？って方は[こちら](https://material.io/design/)！

簡単に言うと、ユーザビリティやユーザーの操作を補助するため、Googleさんが推奨しているデザインパターンです。
陰影をつけて立体的に見せたり、ボタンをタップしたときにエフェクトを表示して押してる感を出したり、色々あります。

今回はそのマテリアルデザインをお手軽に扱うことのできるMaterialComponentsの一部を簡単に紹介したいと思います。

#開発環境
■AndroidStudio3.5

#はじめに
まずはapp/build.gradleを開きましょう。
MaterialComponentsを使用するために以下の確認が必要になります。

・`compileSdkVersion`が28以上かどうか
・AndroidXかそうじゃないかによって、対応するimplementation追加。
※com.google.android.material:materialのバージョンは今回正式リリース版を使います。
　ちなみに2019/12現在の最新は、[1.2.0-alpha02](https://github.com/material-components/material-components-android/releases/tag/1.2.0-alpha02)です。

終わったら`Sync Now`しましょう。

```gradle:app/build.gradle
compileSdkVersion 28以上

dependencies {
    // AndroidXを使用している場合
    implementation 'com.google.android.material:material:1.0.0'

    // AndroidXへ移行できない場合
    implementation 'com.android.support:design:28.0.0'
}
```

##MaterialButton
AppCompatButtonを継承して作られたUIクラスです。
こういう角丸+押下時のエフェクト付きボタンを簡単に実装することが出来ます。

<img width="500" alt="MaterialButton.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222142/964a1e76-f6d7-033f-38d3-f7d772957991.gif">


上記のボタンは、以下のように設定して作っています。

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="vertical"
    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=".MainActivity"
    android:padding="20dp">

    <com.google.android.material.button.MaterialButton
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:textAllCaps="false"
        android:text="MaterialButton"
        android:textAppearance="@style/TextAppearance.MaterialComponents.Button"
        app:backgroundTint="#4169e1"
        app:cornerRadius="20dp"
        style="@style/Widget.MaterialComponents.Button"/>

</LinearLayout>
```

必須なのは、<b>`android:textAppearance`</b>と <b>`style`</b>部分です。
後はプロパティの設定で色々変更することが可能です。
主だったプロパティについて記載します。

####MaterialButtonプロパティ
|プロパティ名|設定内容|
|:-------|:-------|
|**backgroundTint**|ボタンの背景色|
|**cornerRadius**|ボタンの角丸の値（dp指定）|
|**strokeWidth**|ボタンの枠線の太さ（dp指定）|
|**strokeColor**|ボタンの枠線の色|
|**icon**|ボタンにアイコンを表示する|
|**iconSize**|アイコンのサイズ（dp指定）|
|**iconTint**|アイコンの色|
|**iconGravity**|アイコンの位置（start:ボタン左端、textStart:ボタンテキストの左側）|
|**rippleColor**|ripple effect（ボタンタップ時の波紋）の色|

上記のプロパティをいじるだけで、以下のようなボタンをすぐ作れます。
色々いじって試してみてください！
<img width="500" alt="MaterialButton2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222142/7a1b4735-346e-df83-be15-55d5c493448a.gif">



##TextInputLayout + TextInputEditText
お次は入力エリアのMaterialComponentsです。
こんなものが作れます。
<img width="500" alt="TextInputLayout + TextInputEditText.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222142/7b6539ef-0374-0e4d-8f77-340d8e8284a2.gif">

最近のモダンなアプリでは、結構取り入れられていると思うコンポーネントの１つです。
選択時に、ヒントテキストがそのままアニメーション付きでタイトルとしてセットされるため
見た目もリッチでユーザインタフェース的にもわかりやすいので、個人的にかなり気に入っています。

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="vertical"
    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=".MainActivity"
    android:padding="20dp">

    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox">
        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="FilledBox"
            android:imeOptions="actionDone"
            android:inputType="textEmailAddress"
            android:maxLines="1"
            android:textSize="14sp" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:passwordToggleEnabled="true"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="OutlinedBox"
            android:imeOptions="actionDone"
            android:inputType="textPassword"
            android:maxLines="1"
            android:textSize="14sp" />
    </com.google.android.material.textfield.TextInputLayout>

</LinearLayout>
```

使い方は至ってシンプル。
<b>`TextInputLayout`</b>の中に<b>`TextInputEditText`</b>ネストし、
`TextInputLayout`の<b>`style`</b>をセットするだけです。

styleには、FilledBox（入力エリアが塗りつぶされている）とOutlinedBox（入力エリアが枠線付き）が用意されています。
後は先程のMaterialButtonと同様に、TextInputLayoutのプロパティでさらに細かい部分までいじることが出来ます。
こちらも主だったプロパティについて記載します。

###TextInputLayoutプロパティ
|プロパティ名|設定内容|
|:-------|:-------|
|**boxCornerRadius○○**|四辺の角丸設定（左上：TopStart、左下：BottomStart、右上：TopEnd、右下：BottomEnd）|
|**boxBackgroundColor**|入力エリア内の色|
|**boxStrokeColor**|入力エリアの枠線の色（OutlinedBox時のみ有効）|
|**helperText**|入力時の補助となる文言を指定|
|**hintAnimationEnabled**|ヒントがそのままタイトルに移る際のアニメーションON/OFF|
|**passwordToggleEnabled**|パスワードのトグルを有効にするかどうか（ネストされているTextInputEditText->inputTypeをpassword関連にした場合のみ有効）|
|**passwordToggleTint**|パスワードトグルの色|
|**counterEnabled**|入力文字数を表示するかどうか|
|**counterMaxLength**|入力文字数の最大値をセットする。入力文字数1/10みたいなのが作れる（counterEnabledがtrueの場合のみ有効）|


##ChipGroup(Chip)
最後はChipGroupのご紹介です。
関連タグや検索候補などを表示するときに使ったりするMaterialComponentsです。
見た目的にはこういうものになります。

<img width="500" alt="ChipGroup+Chip.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222142/b765ec73-8171-500c-e915-c3060045466a.gif">

xml上での定義は以下のようになります。

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="vertical"
    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=".MainActivity"
    android:padding="20dp">

    <com.google.android.material.chip.ChipGroup
        android:id="@+id/chipGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:singleSelection="true">
        <com.google.android.material.chip.Chip
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="黒柴"
            android:textSize="12sp"
            android:textAppearance="@style/TextAppearance.AppCompat.Small"
            style="@style/Widget.MaterialComponents.Chip.Action"/>
        <com.google.android.material.chip.Chip
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="白柴"
            android:textSize="12sp"
            android:textAppearance="@style/TextAppearance.AppCompat.Small"
            style="@style/Widget.MaterialComponents.Chip.Entry"/>
        <com.google.android.material.chip.Chip
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="赤柴"
            android:textSize="12sp"
            android:textAppearance="@style/TextAppearance.AppCompat.Small"
            style="@style/Widget.MaterialComponents.Chip.Filter"/>
        <com.google.android.material.chip.Chip
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="豆柴"
            android:textSize="12sp"
            android:textAppearance="@style/TextAppearance.AppCompat.Small"
            style="@style/Widget.MaterialComponents.Chip.Choice"/>
    </com.google.android.material.chip.ChipGroup>

</LinearLayout>
```

<b>`ChipGroup`</b>の中に<b>`Chip`</b>をネストすることで、１つのグループとして管理することができるようになります。
グループとして管理する必要がない場合、`Chip`だけで使用することもできます。
感覚としては<b>`RadioGroup`</b>と<b>`RadioButton`</b>の関係性に近いです。

各Chipには`style`として、【.Chip.Action】【.Chip.Entry】【.Chip.Filter】【.Chip.Choice】のどれかを指定して使います。
これらの違いは、タップしたときの選択状態・閉じるボタンの有無などになります。

それぞれの主なプロパティの説明を上げておきます。

###ChipGroupプロパティ
|プロパティ名|設定内容|
|:-------|:-------|
|**checkedChip**|指定したIDのChipをチェック状態にする|
|**chipSpacing,chipSpacing○○**|Chip同士の間隔をセット。Horizontalで横、Verticalで縦のみにも指定可能（dp指定）|
|**singleLine**|１行以上表示できるかどうか（デフォルトはfalse）|
|**singleSelection**|Chipを１つ以上選択できるかどうか（デフォルトはfalse）|

###Chipプロパティ
|プロパティ名|設定内容|
|:-------|:-------|
|**chipIcon,closeIcon**|Chipにアイコンを表示する|
|**chipIconSize, closeIconSize**|アイコンのサイズ（dp指定）|
|**chipIconTint, closeIconTint**|アイコンの色|
|**rippleColor**|ripple effect（ボタンタップ時の波紋）の色|
|**chipCornerRadius**|Chipの角丸の値（dp指定）|
|**chipBackgroundColor**|Chipの背景色|
|**chipStrokeWidth**|Chipの枠線の太さ（dp指定）|
|**chipStrokeColor**|Chipの枠線の色|

こちらのComponentにはsetOnClickListenerの他にも
`setOnCheckedChangeListener`, `setOnCloseIconClickListener`などといった
チェック時や閉じるボタンの動作を検知するためのリスナーも用意されていますので、
用途によって色々な実装をすることも可能です。

#おわりに
いかがだったでしょうか？
それぞれ、自分でイチから実装しようと思うと、基本の機能を拡張したり、アニメーションさせたりとてつもなく面倒ですが、
xmlへの定義だけで、これだけのコンポーネントが使えるのは素直にスゴいですよね！！
今後も定期的に追加されていくはずなので楽しみです。

今回はソース側からの操作については記載しませんが、他にも色々できるのでぜひご自身で試してみてください！