MaterialButtonについ調べたことメモ。
環境 : com.google.android.material:material:1.4.0
デフォルトで当たるstyle
結論
多くのThemeの場合、@style/Widget.MaterialComponents.Button
詳しく
まずMaterialButton
のコンストラクタを見てみる。
![]() |
---|
→R.attr.materialButtonStyle
である。
※ちなみに、xmlからinflateした場合、引数が2つ(View(Context context, AttributeSet attrs)
)のコンストラクタが呼ばれます。
ではR.attr.materialButtonStyle
の内容は?
→多くのThemeの場合、@style/Widget.MaterialComponents.Button
![]() |
---|
※Base.V14.Theme.MaterialComponents.Bridge
はTheme.MaterialComponents.NoActionBar
などの親。
※ただし、ほかにも、@style/Widget.MaterialComponents.Button.TextButton.Dialog.Flush
のことなどもなくはない。
![]() |
---|
おまけ : @style/Widget.MaterialComponents.Button
の内容
こんな感じ。
![]() |
---|
だれがripple
つきの背景を作成しているか
MaterilaButton
はrippleがデフォルトでつきます。
しかし@style/Widget.MaterialComponents.Button
にはrippleの設定のような部分があるにもかかわらずほかのView
のthemeやstyleとして指定してもrippleがつきませんでした。
そこでMaterialButton
がどのようにrippleを作成しているか調べました。
結論
MaterilaButton
の見た目の一部の設定を担っているMaterilaButtonHelper
がbackgroundTint
やrippleColor
の値を考慮しつつ背景のdrawableとしてRippleDrawable
というLayerDrawable
を設定している。
詳しく
「MaterilaButtonHelper
がMaterilaButton
の見た目の一部の設定を担っている」
この辺り。MaterilaButton
のコンストラクタで、MaterilaButtonHelper
にAttributeと自身を渡して、色々とセットしてもらっている。
※コメントにはbackgroundのことだけをやっている風に書いてあるけど、実際のコードをみるとelevationのこともやっているように見える?
![]() |
---|
MaterilaButtonHelper
「backgroundTint
やrippleColor
の値を考慮しつつ背景のdrawableとしてRippleDrawable
というLayerDrawable
を設定している。」
- 先ほど呼ばれていた
MaterilaButtonHelper#loadFromAttributes
- の中で、
MaterilaButtonHelper#updateBackground
が呼ばれているが
- その中で
MaterilaButtonHelper#createBackground
を呼びRippleDrawable
を作成し、それを背景としてセットしている。
-
MaterilaButtonHelper#createBackground
メソッド
![]() |
---|
- 特にこの辺りで
RippleDrawable
を作成。
![]() |
---|
- ちなみに
rippleColor
などは、MaterilaButtonHelper#loadFromAttributes
で渡されたAttributeから読み込んでいます。
![]() |
---|
<item name="rippleColor">
で設定した値ですね。
ちなみに
android:background
を設定してしまうと、このrippleつきの自動生成背景がつけてもらえなくなります。
それはMaterilaButtonHelper#loadFromAttributes
でandroid:background
があるときはMaterilaButtonHelper#updateBackground
ではなくMaterilaButtonHelper#setBackgroundOverwritten
が呼ばれるようになっており
![]() |
---|
MaterilaButtonHelper#setBackgroundOverwritten
ではrippleの生成などは全く行わないからです。
![]() |
---|
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
のこの辺り
![]() |
---|
「@style/Widget.MaterialComponents.Button
のinsetTop
とinsetBottom
の値はnon-zero」
-
@style/Widget.MaterialComponents.Button
のinsetTop
とinsetBottom
の値
![]() |
---|
@dimen/mtrl_btn_inset
です。
※加えて、insetRight
とinsetBottom
は0dpなこともわかると思います。
@dimen/mtrl_btn_inset
![]() |
---|
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
である」と言っていいと思います。