こんにちは!Diverse Advent Calendar 2019の19日目を担当するasmzです。
現在、Diverseにてyycという老舗マッチングサービスのAndroidアプリエンジニアをやっております。
今回、ブログを書くに当たって何にしようかなーと思いましたが個人的に興味のあるAndroid10から導入されたDarkThemeについて書こうと思います!
↓だいたいこのへんに書いてあることをまとめてるかんじです。
https://developer.android.com/guide/topics/ui/look-and-feel/darktheme
https://material.io/develop/android/theming/color/
https://material.io/develop/android/theming/dark/
ダークテーマの何が良いの?
- 電源の利用相当量が抑えられる(どのくらい差があるかは端末に依ります)
- 視力が低いユーザー、明るい光に敏感なユーザーの視認性向上
- 照度が低い(暗い)環境下で使いやすい
などといった利点があります。いいことが多いですね。私もダークテーマ愛用中です。
どうやってダークテーマ対応アプリをダークテーマ状態で使うの?
Android10(API level 29)以上でダークテーマ対応アプリでダークテーマを利用するにはには、以下の3つの方法があります
- システム設定のSetting -> Display -> Themeでダークテーマを選択
- 通知トレイのクイックメニューでダークテーマをONにする
- Pixelであればバッテリーセーブモードにしたときに同時にダークモードになる(他のOEM端末だとならないこともある)
自分のアプリのダークテーマを有効にするには?
/res/value/styles.xmlにあるアプリ全体のテーマのParentをダークテーマ対応にすればできます。
<style name="AppTheme" parent="Theme.AppCompat.DayNight">
MaterialComponentの親Themeでも可能。
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
これでアプリのメインテーマがシステム管理下のNightModeFlagに紐付けられて、必要に応じてDarkThemeが適応されます!
ちなみに私の担当しているyycで試しにonにしてみたらCardViewの背景色のみ変更されました。笑い事。
(CardViewの背景色を指定していないため、そこだけ反映されたと思われる)
ThemeとStyle
ThemeとStyleは、ライトテーマのみで使うのを前提にハードコードしないように気をつけましょう。(したので↑のような状態になっている)
それを回避するためには、テーマの属性を使用するか、夜間用リソースを通常リソース以外に用意しましょう。
どうやらGoogle的には夜間用リソースを別途利用するよりも、テーマ属性で管理すること、特にMaterialDesignComponentsの、ColorThemingSystemを使うことをおすすめしているようです。
ColorThemingSystemは、attr/colorSurface
や?attr/colorOnSurface
等の汎用的なAttributesを設定することで、Dark/Lightのテーマを個別に設定しなくてもどうにかなるようにしているようです。
https://material.io/develop/android/theming/color/
詳しくは、↑にAttributesについての説明があるので見て下さい。
Android公式を見ると、以下のようなことに気をつけてね、と書いてあります。
- 背景色は常に明るい色だという思い込み
- テキストの色をハードコーディングする
- デフォルトのテキスト色を使用しながら、背景色をハードコードする
- 静的な色のドローアブル アイコンの使用 基本的に「Light前提のThemeのカラー設計にしない」と「ハードコーディングやめよう」ですね! 「色名」での指定はやめましょう。
超簡単ダークテーマ対応:矯正ダーク
でも古くからのアプリはそんな簡単にダークテーマ化できる!なんて思わないですよね。そんなきれいにcolorは切っていないわ、直接whiteとかblackとかlayoutに指定している場合も結構あると思います。
Android10では、通常のLightThemeで作成しているアプリを強制的にDarkTheme化する機能がやります!
その名も矯正ダーク!(Android公式翻訳でそういう名前になってます)
矯正ダークはLightテーマの各Viewを解析して、表示タイミングで「ダークテーマっぽい」色に変えてくれるシステムです。
矯正ダークは、ActivityのThemeにandroid:forceDarkAllowed="true"
と書くだけで有効になります。
あくまでLight
のThemeのものをダークテーマっぽい色に変換するので、AppThemeがDayNight
だと適用されないので気をつけてください。
また、あるViewは矯正ダーク化したくない、という需要もあるかと思います。その場合はそのViewにandroid:forceDarkAllowed="false"
を要素に加えることで矯正ダーク化されないようになります。
ちなみにやってみました。
だいぶそれっぽい感じになってますね!例えばカードの境目が見えない、右上のActionアイテムの選択中と下のバーの色が違う、等の違和感はありますが目をつぶりましょう。(モザイクのサイズに関してはちょっと手順逆になっただけなのでつっこまないでください)
背景は色が変わらないのに「あと5人」の背景色等が全然違って気持ち悪い色合いになってますね!
ここの背景は画像なので、その場合は変換がかからないようです。
https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources
こういうときの必殺技として、リソースファイルを切るという方法もあります。
drawable-xhdpi
,drawable-xxhdpi
等、drawableファイルを複数用意するのは結構やっている方が多いと思いますが、それと同様にnightモード用のリソースを用意することが可能です。
代替リソースに関してはLight
モードであっても適用されるので、矯正ダーク時でもnightの代替リソースの方が利用されます。
たとえば、drawable-xhdpi
のNight
モードを用意したい場合は、drawable-night-xhdpi
ディレクトリを切ってください。(逆にするとコンパイル時にエラーが出ます。)
drawable-night-xhdpi
でNight
用の背景、layout-night
でルートにforceDarkAllowed="false"
を設定してちまちまと色あいを修正してみました。
←ただ矯正ダークにした 代替リソースで背景画像と専用レイアウトを修正した→
雑に修正をした割には、だいぶマシかつダークモードっぽくなったのではないでしょうか!
なので、矯正ダークモードを使うと微妙になってしまう画面があったとしたら、代替リソースでその画面だけ対応する、という手もあります。
もしかしたら、色だけvalue-nightでナイトモード用に切る、という方法もありかもしれません!
個人的には、例えば個人でやっているアプリで、そこまでビジュアルにこだわらない場合は、矯正ダークを適用してしまうのも一つの手だと思うレベルで、結構ちゃんとそれっぽくしてくれますので、一度試してみるのもありかと思います!
おわりに
DarkThemeは、特にバッテリーが弱い格安端末等が利用される地域で、今後より求められる機能だと思われます。
早め早めの対応で、試してみるのもいいのでは?と思います!
宣伝
ええーっと、今回この記事を書いた理由が一つありまして。
https://droidkaigi.jp/2020/
DroidKaigiでダークテーマについて話すことになりましたので、どうぞよろしくお願いいたします。
多分この話とも重複するとは思うので、そこは生ぬるくお願いします。