Button・AppCompatButton・MaterialButtonの違いを知りたい


[前回の記事](https://qiita.com/satona-oinuma/items/82053ee3ed3ac82344a0)を作成した際、ボタンには種類があることに気づきました。
今回はその違いを理解すべく、以下の3種類について調べました。

- `Button`
- `androidx.appcompat.widget.AppCompatButton`
- `com.google.android.material.button.MaterialButton`

調べてはみたものの、自分の未熟さを痛感しながらの作業となりました。
認識が間違っている、正しい情報ではない等ありましたら、ぜひコメントをお願いいたします。


## 1.Button

ユーザーがタップまたはクリックしてアクションを実行できるUIコンポーネントです。
こちらが最も基本のクラスであり、Android1.0（APIレベル1）から使用することができます。
（参考：[Android Developer: Button](https://developer.android.com/reference/kotlin/android/widget/Button )）

### 使用例
```kotlin:activity_main.xml
<Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />
```
上記コードを記述すると以下のようなボタンが表示されます。
![nothehme-button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1396691/21791766-ed84-9349-6f6a-48708098c554.png)
今回は`Button`として表示させるべく、テーマの継承を無効にして実装しました。
`Button`は、AppCompatテーマを継承した場合は`AppCompatButton`として、同様にMaterialComponentsテーマを継承した場合は`MaterialButton`として拡張する特徴があります。


テーマの継承の指定は、以下のようにstyleのparent属性で行います。

```kotlin:res/values/themes.xml
<resources xmlns:tools="http://schemas.android.com/tools">
    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <item name="colorPrimary">@color/black</item>
        <item name="colorOnPrimary">@color/purple_200</item>
    </style>
</resources>
```



## 2.AppCompatButton

AppCompatライブラリ適用のボタンクラスであり、Buttonクラスのサブクラスです。

[AppCompat](https://developer.android.com/jetpack/androidx/releases/appcompat?hl=ja)とは、新しいフレームワークやメソッドなどを以前のAPIバージョンでも使えるようにするためのライブラリです。
元々は[SupportLibrary](https://developer.android.com/topic/libraries/support-library)というライブラリで提供されていましたが、2018年のAndroid9.0（APIレベル28）のリリース以降は[AndroidX](https://developer.android.com/jetpack/androidx)として提供されています。（参照：[Hello World, AndroidX](https://android-developers.googleblog.com/2018/05/hello-world-androidx.html)）
※AndroidXライブラリとは、SupportLibraryを大幅に改良したものです。

2021/06/28現在、AndroidStudio（使用環境：AndroidStudio 4.1.1）で新しく作成したプロジェクトはAppCompatがデフォルトで使用できるようになっています。

### AppCompatを使用するための条件
AppCompatを使用するには以下3点を満たしている必要があります。

①AndroidXが使用できるプロジェクトである
②GoogleのMavenリポジトリがプロジェクトに追加されている（参照：[ビルド依存関係を追加する](https://developer.android.com/studio/build/dependencies?hl=ja#google-maven)）
③モジュールレベルのGradleファイルに[AppCompatライブラリ](https://maven.google.com/web/index.html#androidx.appcompat:appcompat)が追加されている

上記の条件をコードで表すと以下の通りとなります。

①AndroidXが使用できるプロジェクトである

```kotlin:MyApplication/gradle.properties
android.useAndroidX=true //trueであること
android.enableJetifier=true //trueであること
```
```kotlin:app/build.gradle
android {
    compileSdkVersion 30 //バージョンが28以上であること
}
```

②GoogleのMavenリポジトリがプロジェクトに追加されている

```kotlin:MyApplication/build.gradle
allprojects {
    repositories {
        google() //Mavenリポジトリの追加
        jcenter()
    }
}
```

③モジュールレベルのGradleファイルにAppCompatライブラリが追加されている

```kotlin:app/build.gradle
dependencies {
    implementation 'androidx.appcompat:appcompat:1.3.0' //ライブラリの追加
}
```

### AppCompatButtonの使用例
```kotlin:activity_main.xml
<androidx.appcompat.widget.AppCompatButton
        android:id="@+id/appcompat_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/app_compat_button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/button"
        />
```
上記コードを記述すると以下のようなボタンが表示されます。
![appcompatbutton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1396691/140f6228-6991-8ad3-74ec-6acecf0e0b72.png)
（継承するテーマとしてTheme.AppCompat.DayNight.DarkActionBarを指定した場合）

ちなみに、テーマを指定しない場合は以下のようにただのテキストのようになりますが、ボタンとしての機能は維持されています。
![notheme-appcompat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1396691/726b3be3-7fe5-4084-ed44-a44f3a7bac0f.png)


## 3. MaterialButton

[マテリアルデザイン](https://material.io/)が利用できるボタンクラスであり、AppCompatButtonクラスのサブクラスです。

MaterialButtonはAppCompatButtonのサブクラスであるため、下位互換などの機能はそのままに、マテリアルデザインに則っているため操作がしやすいという特徴があります。


2021/06/28現在、AndroidStudio（使用環境：AndroidStudio 4.1.1）で新しく作成したプロジェクトはMaterialComponentsがデフォルトで使用できるようになっています。

### MaterialComponentsを使用するための条件
MaterialComponentsを使用するには以下3点を満たしている必要があります。

①GoogleのMavenリポジトリがプロジェクトに追加されている
②モジュールレベルのGradleファイルに[MaterialComponentsのライブラリ](https://maven.google.com/web/index.html#com.google.android.material)が追加されている
③compileSdkVersionが29以上である

上記の条件をコードで表すと以下の通りとなります。

①GoogleのMavenリポジトリがプロジェクトに追加されている

```kotlin:MyApplication/build.gradle
allprojects {
    repositories {
        google() //Mavenリポジトリの追加
        jcenter()
    }
}
```

②モジュールレベルのGradleファイルにMaterialコンポーネントのライブラリが追加されている

```kotlin:app/build.gradle
dependencies {
    implementation 'com.google.android.material:material:1.3.0' //ライブラリの追加
}
```

③compileSdkVersionが29以上である

```kotlin:app/build.gradle
android {
    compileSdkVersion 30 //29以上であること
dependencies {
    implementation 'com.google.android.material:material:1.3.0' //ライブラリの追加
}
```

### MaterialButtonの使用例

#### MaterialComponentsテーマから継承する場合

以下の手順で実装していきます。
①継承するテーマを設定する
②色を設定する
③レイアウトファイルにボタンを追加する

```kotlin:res/values/themes.xml
<resources xmlns:tools="http://schemas.android.com/tools">
    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> // ①テーマを設定
        <item name="colorPrimary">@color/black</item> // ②ボタン背景に反映される色を指定
        <item name="colorOnPrimary">@color/purple_200</item> // ②文字色に反映される色を指定
    </style>
</resources>
```
```kotlin:res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
       <color name="black">#FF000000</color>
       <color name="purple_200">#FFBB86FC</color>
</resources>
```
```kotlin:activity_main.xml
<com.google.android.material.button.MaterialButton // ③MaterialButtonを追加
        android:id="@+id/material_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/material"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/appcompat_button"
        />
```
以上のコードを記述すると記述以下のようなボタンが表示されます。
![material.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1396691/1d1209d1-fcdf-b52b-55a6-3e55df7c6bb3.png)

ここでの注意点は、③で追加した`<com.google.android.material.button.MaterialButton`はMaterialComponentsテーマでのみ使用できるという点です。
MaterialComponentsテーマ以外を継承すると以下のエラーが出ます。
`Error inflating class com.google.android.material.button.MaterialButton`

#### AppCompatテーマから継承する場合

以下を参考にAppCompatテーマを継承して MaterialComponentsテーマから継承する場合 と同じボタンの作成を試みましたが、作ることはできませんでした。

>Note: Since this is the default type, you don't need to specify a style tag as long as you are using a Material Components Theme. If not, set the style to @style/Widget.MaterialComponents.Button.
[Buttons – Material Components for Android](https://material.io/components/buttons/android#contained-button) 

ただしマテリアルデザインのようなボタンにはなったため、参考までに記載します。

以下の手順で実装していきます。
①継承するテーマを設定する
②色を設定する
③レイアウトファイルにボタンを追加する
④style属性にMaterialコンポーネントを追加する

```kotlin:themes.xml
<resources xmlns:tools="http://schemas.android.com/tools">
    <style name="Theme.MyApplication" parent="Theme.AppCompat.DayNight.DarkActionBar"> // ①AppCompatテーマを設定
        <item name="colorPrimary">@color/black</item> 
        <item name="colorOnPrimary">@color/purple_200</item> // ②文字色に反映される色を指定
<item name="textAppearanceButton">@style/TextAppearance.MaterialComponents.Button</item>
    </style>
</resources>
```
以下、レイアウトファイルを`Button`で指定していますが、`androidx.appcompat.widget.AppCompatButton`でも同じように表示されます。

```kotlin:activity_main.xml
<Button // ③ボタンを追加
        android:id="@+id/material_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/material"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/appcompat_button"
        style="@style/Widget.MaterialComponents.Button" // ④Materialコンポーネントのスタイルを指定
        />
```
以上を記述し、以下のようなボタンが表示されました。
![materialbutton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1396691/4e8a17ee-ef1d-df5c-43d3-30be8f2dbdae.png)


## まとめ：ボタン種別ごとの比較

### ButtonとAppCompatButton
「AppCompatテーマを継承している場合、ButtonはAppCompatButtonに拡張されるため差はない」
書き方が統一されていれば、どちらで書いても良さそうです。
AppCompatライブラリが追加されていないモジュールの場合はButtonを使うしかありませんが、今からアプリを作るのであればAppCompatライブラリを使うべきです。

### ButtonとMaterialButton
「MaterialComponentsテーマを継承している場合、ButtonはMaterialButtonに拡張されるため差はない」
こちらも書き方が統一されていれば、どちらの書き方でも問題なさそうです。
`com.google.android.material.button.MaterialButton`の記述がある際にMaterialComponentsテーマ以外のものから継承するとエラーが出るため、その点は注意が必要です。

### AppCompatButtonとMaterialButton
「全体にマテリアルデザインを対応させたい場合はMaterialButtonを使用する」
AppCompatButtonはMaterialComponentsテーマを使用していても自動的にマテリアルデザインになるわけではありません。そのため、デザインにこだわりたいという場合は`com.google.android.material.button.MaterialButton`としてボタンを追加する必要があるようです。ただし、レイアウトにこだわらなくても良い場合は無理にマテリアルボタンを使う必要はないと分かりました。

##おわりに
以上3種類のボタンについて見てきました。
今回はボタンに焦点を当てましたが、ボタン要素はUIコンポーネントの一部であり、他の機能面や全体のテーマを総合的に見て統一を図ることが望ましいと分かりました。
今回の3種類のボタンを起点に、AppCompatやMaterialコンポーネントについても理解を深めていきたいと思います。