(今から新規でアプリ作るなら、Material Components使うほうがオススメだよ!)
AppCompat.Buttonスタイル
とにもかくにも、スタイル定義を理解するためにも、AppCompat.Button
を理解しましょう。
AppCompat.Button
には主に以下の4種類のスタイルがあります。
- Widget.AppCompat.Button
- Widget.AppCompat.Button.Colored
- Widget.AppCompat.Button.Borderless
- Widget.AppCompat.Button.Borderless.Colored
Default | backgroundTint="#4DB6AC" |
---|---|
|
当然、Borderlessスタイルは背景がないのでtintされません。
AppCompat.Button
Androidの標準のボタンです。
旧マテリアルデザインではRaised Button、現在のマテリアルデザインではContained Buttonなどと呼ばれています
TextAppearance
?android:textAppearanceButton = TextAppearance.AppCompat.Widget.Button
AppCompat.Buttonの色
enabled | disabled1 | |
---|---|---|
background | ?colorButtonNormal |
?colorButtonNormal |
textColor2 | ?android:textColorPrimary |
?android:textColorPrimary |
Ripple | ?colorControlHighlight |
- |
サイズ
AppCompat.Button
のminHeight
は48dpです。
しかし、実際表示してみると明らかにそれより小さいことがわかると思います。
これは、AppCompat.Button
に指定されているbackground
リソースにインセットが設けられているためです。
それぞれ、上下に6dp、左右に4dpのインセットが設定されています。
結果的に、
48dp (minHeight) - 6dp (insetTop) - 6dp (insetBottom) = 36dp
が見た目上の高さとなっています。
なお、この設定は旧マテリアルデザインのスペックに沿っています。
現在のマテリアルデザインガイドラインではコンポーネントのサイズと見た目のサイズを違えるという記述は消えているため、そのうちなくなるかもしれません。
(そもそもAppCompatよりもMaterial Componentsが推奨されていく可能性のほうが高いと思いますが)
elevation
AppCompat.Button
の特徴としてelevation
が設定されています。
ただし、このelevation
はandroid:elevation="0dp"
としても無効にすることはできません。
AppCompat.Button
のelevation
は、実際はandroid:stateListAnimator
によって制御されているため、無効にしたい場合はandroid:stateListAnimator="@null"
とする必要があります。
AppCompat.Button.Colored
AppCompat.Button
のサブスタイルで、ボタンに適用されるテーマのcolorAccent
の色になるボタンです。
TextAppearance
TextAppearance.AppCompat.Widget.Button.Colored
AppCompat.Button.Coloredの色
enabled | disabled | |
---|---|---|
background | ?colorAccent |
?colorButtonNormal |
textColor | ?android:textColorPrimaryInverse |
?android:textColorPrimary 1
|
Ripple | ?colorControlHighlight |
- |
ただ単にtintする場合、AppCompat.Button
とAppCompat.Button.Colored
どちらのスタイルを使うかについては、ボタンの明度がLightかDarkかで決めていいと思います。(ざっくりテキストがInverseかどうかの差です)
AppCompat.Button.Borderless
旧マテリアルデザインではFlat Button、現在はText Buttonと呼ばれているボタンです。
AppCompat.Button
のbackgroundからshapeを除いているだけです。
TextAppearance
?android:textAppearanceButton = TextAppearance.AppCompat.Widget.Button
AppCompat.Button.Borderlessの色
enabled | disabled1 | |
---|---|---|
background | - | - |
textColor | ?android:textColorPrimary |
?android:textColorPrimary |
Ripple | ?colorControlHighlight |
- |
AppCompat.Button.Borderless.Colored
AppCompat.Button.Borderless
のテキストに色付けをおこなったスタイルです。
AppCompat.Button.Borderlessの色
enabled | disabled | |
---|---|---|
background | - | - |
textColor | ?colorAccent |
?android:textColorSecondary 1
|
Ripple | ?colorControlHighlight |
- |
AppCompat.Button系スタイルの色はどう指定するのがよいか?
AppCompat.Button
系スタイルの色の変え方には2種類あります。
1つは、最初に扱ったbackgroundTint
を利用する方法です。
2つめは、ThemeOverlay
を利用する方法です。
それぞれにメリット・デメリットが存します。
backgoundTint
backgroundTint
とは、background
にあてた画像リソースにカラーフィルタをかけて色を変化させる属性です。
対応するminSdkVersionによって利用できるネームスペースが違うので気をつけてください。
Androidバージョン | app:backgroundTint | android:backgroundTint |
---|---|---|
21未満 | o | x |
21+ | o | o (推奨) |
backgroundTint
に指定できるのは、ColorリソースまたはColorStateListリソースになります。
ColorStateListとは以下のような定義をしたリソースを指します。3
<selector>
<item android:state_enabled="false" android:color="@color/disabled_color"/>
<item android:color="@color/enabled_color"/>
</selector>
メリット
レイアウト時に即席でどんな色でも当てられるので、デメリットを気にしない場合はデザインの要求に対してコストが圧倒的に低いです。
<Button
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/red"
android:text="Red Button"/>
デメリット
ステート対応がめんどくさい。
特殊なステートの場合はどっちにしろめんどくさいのですが、enabled - disabledの状態にすらColorStateListを作る必要があります。
将来的に、ColorStateListリソースがres/drawableに大量に作られて管理しきれなくなります。
ThemeOverlay
ThemeOverlayとは、View及びViewGroup階層でテーマの任意の変数をオーバーライドする手法です。
theme
属性で指定しますが、これについても対応するminSdkVersionによって利用できるネームスペースが違います。
Androidバージョン | app:theme4 | android:theme |
---|---|---|
21未満 | o | x |
21+ | o | o (推奨) |
ThemeOverlayの適用範囲は、そのView及びそれ以下のView階層です。
ThemeOverlayを使ったボタンの色の変更は、以下のようにします。
<Button
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Red Button"
android:theme="@style/ThemeOverlay.Button.Red"/>
<style name="ThemeOverlay.Button.Red" parent="ThemeOverlay">
<item name="colorAccent">@color/red</item>
</style>
AppCompat.Button.Colored
の色は、先述したように?colorAccent
が利用されるため、ThemeOverlayでその値だけ変更することでボタンの色が変更できます。
メリット
既存のボタンのステート定義を尊重しつつ、部分的に色を変更できる。
ThemeOverlayで当てる場合、?colorAccent
のみを変更しているためdisabled状態は変わらず標準の表現が使われます。
逆にdisabledの色も任意にやりたい場合は、?colorButtonNormal
を変更すればいいだけです。
デメリット
即席で色を当てる用途で使うには手間がかかる。
テーマを定義しないといけないため、1箇所でしか使わないボタンスタイルのためにやる作業としては、コストが重いように感じます。
ボタンのスタイル管理
ここまで、AppCompat.Button
系スタイルの話しかしませんでしたが、独自スタイルにおいても同じことが言えます。
そのためAppCompat.Button
を理解することで、独自定義の方法や何を懸念するべきかということも見えてくるはずです。
例えば今僕の携わっているプロジェクトでは、アウトラインボタンという枠線のみのボタンスタイルが定義されていますが、AppCompat.Button
を参考にdrawable
、textAppearance
、style
の定義を行っています。
結局tintとthemeどちらを利用すればいいか
ハッキリ言って一貫した答えはありません。
画面仕様、デザインの指定から読み取ったり、デザイナーさんに訊いてみるのが手っ取り早いです。
目安としては
- disabledステートが必要なら
ThemeOverlay
- とりあえず色付きのボタンが置ければいいなら
backgroundTint
くらいの認識でいいと思います。