MaterialButtonのthemeとか調べたことまとめ

MaterialButtonについ調べたことメモ。

環境 : `com.google.android.material:material:1.4.0`

# デフォルトで当たるstyle

## 結論

多くのThemeの場合、`@style/Widget.MaterialComponents.Button`

## 詳しく

### まず`MaterialButton`のコンストラクタを見てみる。
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/82930bd0-3cc8-8f03-39f5-7fb98a63dc8d.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButton.java#L220

**→`R.attr.materialButtonStyle`である。**


※ちなみに、xmlからinflateした場合、[引数が2つ(`View(Context context, AttributeSet attrs)`)のコンストラクタが呼ばれます。](https://qiita.com/alzybaad/items/aca3049b6a13ab78f945)

### では`R.attr.materialButtonStyle` の内容は?


**→多くのThemeの場合、`@style/Widget.MaterialComponents.Button`**



|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/51407eb5-03a9-f89b-a6a5-aa117fd811ba.png)|
|--|


https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/theme/res/values/themes_base_bridge.xml#L62

※`Base.V14.Theme.MaterialComponents.Bridge`は`Theme.MaterialComponents.NoActionBar`などの親。


※ただし、ほかにも、`@style/Widget.MaterialComponents.Button.TextButton.Dialog.Flush`のことなどもなくはない。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/7fb5b3ee-11d9-66d7-7aee-2b6fba03bda2.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/dialog/res/values/themes_base.xml#L116

#### おまけ : `@style/Widget.MaterialComponents.Button`の内容

こんな感じ。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/4a6ee1d4-53cd-b3c4-2bbb-e50f61a1cc94.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/res/values/styles.xml#L23


# だれが`ripple`つきの背景を作成しているか

`MaterilaButton`はrippleがデフォルトでつきます。
しかし`@style/Widget.MaterialComponents.Button`には[rippleの設定のような部分があるにもかかわらず](https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/res/values/styles.xml#L45)ほかの`View`のthemeやstyleとして指定してもrippleがつきませんでした。
そこで`MaterialButton`がどのようにrippleを作成しているか調べました。


## 結論

`MaterilaButton`の見た目の一部の設定を担っている`MaterilaButtonHelper`が`backgroundTint`や`rippleColor`の値を考慮しつつ背景のdrawableとして`RippleDrawable`という`LayerDrawable`を設定している。

## 詳しく

### 「`MaterilaButtonHelper`が`MaterilaButton`の見た目の一部の設定を担っている」

この辺り。`MaterilaButton`のコンストラクタで、`MaterilaButtonHelper`にAttributeと自身を渡して、色々とセットしてもらっている。
※コメントにはbackgroundのことだけをやっている風に書いてあるけど、実際のコードをみるとelevationのこともやっているように見える？

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/62dd005a-dfe9-46d0-6f80-05fa7e83d53b.png)|
|--|


https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButton.java#L249

- `MaterilaButtonHelper`
 
https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java


### 「`backgroundTint`や`rippleColor`の値を考慮しつつ背景のdrawableとして`RippleDrawable`という`LayerDrawable`を設定している。」

- 先ほど呼ばれていた`MaterilaButtonHelper#loadFromAttributes`

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L82


- の中で、`MaterilaButtonHelper#updateBackground`が呼ばれているが

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L125

- その中で`MaterilaButtonHelper#createBackground`を呼び`RippleDrawable`を作成し、それを背景としてセットしている。

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L137

- `MaterilaButtonHelper#createBackground`メソッド

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/fc52e781-8f37-1f43-32c2-b5df8f16d379.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L202

- 特にこの辺りで`RippleDrawable`を作成。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/59629df0-9976-098a-7037-32e6f697de70.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L225


- ちなみに`rippleColor`などは、`MaterilaButtonHelper#loadFromAttributes`で渡されたAttributeから読み込んでいます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/ff32ca93-febf-56dd-a448-14f7d0624d3c.png)|
|--|

 
https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L108

`<item name="rippleColor">`で設定した値ですね。

## ちなみに

`android:background`を設定してしまうと、このrippleつきの自動生成背景がつけてもらえなくなります。    
それは`MaterilaButtonHelper#loadFromAttributes`で`android:background`があるときは`MaterilaButtonHelper#updateBackground`ではなく`MaterilaButtonHelper#setBackgroundOverwritten`が呼ばれるようになっており

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/d6421034-ab01-8a61-e21a-14a7956546d7.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L122

`MaterilaButtonHelper#setBackgroundOverwritten`ではrippleの生成などは全く行わないからです。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/efc6120e-c7e0-a4a6-e655-97b8e3a5add7.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L149

# AppCompatButtonに比べて、余分につく`padding`はどこが原因?

AppComapt系のthemeがあたった`Activity`にinflateするxmlの`Button`とMaterial系のそれでは、同じ`android:paddingTop`を設定しても実際のUI表示を確認するとMaterial系のそれの方が若干paddingが多くなってしまいます。その原因を探りました。

## 結論
`MaterialButton`では、`MaterialButtonHelper`がAttributeからpaddingを設定するときに`android:paddingXXX`と`android:insetXXX`を加算した値を実際のpaddingとして使用し、`@style/Widget.MaterialComponents.Button`の`insetTop`と`insetBottom`の値はnon-zeroだから。


## 詳しく
### 「`MaterialButtonHelper`がAttributeからpaddingを設定するときに`android:paddingXXX`と`android:insetXXX`を加算した値を実際のpaddingとして使用」

`MaterilaButtonHelper#loadFromAttributes` のこの辺り

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/8c8a08d5-865d-9c74-4a14-ddb434ddaf0d.png)|
|--|


https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/MaterialButtonHelper.java#L128

### 「`@style/Widget.MaterialComponents.Button`の`insetTop`と`insetBottom`の値はnon-zero」

- `@style/Widget.MaterialComponents.Button`の`insetTop`と`insetBottom`の値

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/156d9118-9a59-976a-4d9c-f61278372c64.png)|
|--|

https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/res/values/styles.xml#L37

`@dimen/mtrl_btn_inset` です。
※加えて、`insetRight`と`insetBottom`は0dpなこともわかると思います。

- `@dimen/mtrl_btn_inset`

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245217/aefe30be-0364-5a0d-2698-b56d049a26db.png)|
|--|


https://github.com/material-components/material-components-android/blob/1.4.0/lib/java/com/google/android/material/button/res/values/dimens.xml#L19

6dpです。

よって、`MaterialButtton`ではデフォルトだと同じ値を`android:paddingTop`などで指定しても`AppCompatButton`よりTopとBottomのpaddingは少し大きくなってしまいます。
同じにしたいときは`android;insetXXX`をすべて0dpにする必要があります。

※ 厳密にはこれだけでは「差異の原因が`android:insetXXX`である」とは言えません(`AppCompatButton`も`android:insetXXX`を見ているかもしれない)が、`AppCompatButton`や`Button`のコードに`android:insetXXX`を見ている部分はみつけられず、また`MaterialButton`は`AppCompatButton`の子クラスですが`android:insetXXX`は`MaterialButton`の`XML attributes`として公式ドキュメントに書かれているので「`AppCompatButton`は`android:insetXXX`は見ていない」「差異の原因が`android:insetXXX`である」と言っていいと思います。

https://developer.android.com/reference/com/google/android/material/button/MaterialButton#attr_MaterialButton_android_insetTop




# 参考文献
- https://qiita.com/alzybaad/items/aca3049b6a13ab78f945