これからAndroidでダークモードを実装するエンジニア／デザイナ向け資料

### 追記: 20191017
Android 10ではコントロールセンターからダークモードが切り替え可能になり「システムに従う」「バッテリー状態によって切り替える」設定が追加されました。くわしくは[こちら](
https://qiita.com/keidroid/items/7452a6988011664eb8d9)

### 追記: 20190509
Google I/O 2019で公式のダークテーマのデザインガイドラインとオンライン学習ページが公開されました。
 - https://material.io/design/color/dark-theme.html
 - https://codelabs.developers.google.com/codelabs/design-material-darktheme/

# はじめに

去年末にQiitaに投稿した「[スマホアプリ開発者のための2018年動向まとめ](https://qiita.com/keidroid/items/88ee170f8bc697d4f7e9)」でダークモードについて少し書いたのですが、2019年になってからダークモードのニュースが増えているような気がします。
今風の表現で言えば2019年は"ダークモード元年"になりそうな予感(？)です..!

↓Androidでダークモード？

> Android Qの初期ビルドが出回る。噂のダークモードに加え、DeX的なデスクトップモードも搭載か
> https://japanese.engadget.com/2019/01/17/android-q-dex/

↓iOSもダークモード？？

> iOS 13でついにiPhoneにダークモードが登場か、バッテリー消費を劇的に抑えられるかも
> http://gigazine.net/news/20190203-ios-13-dark-mode/

↓Chromeでもダークモード？？？

> Chrome Canary now supports dark mode in Windows 10 and respects light/dark mode Setting
> https://techdows.com/2019/02/chrome-canary-now-supports-dark-mode-in-windows-10-and-respects-light-dark-mode-setting.html

個人的に出しているニュースリーダーアプリにも1月にダークモードを実装したので
そのときに得たデザインのノウハウや実装方法についてまとめます。

↓こんなの
<img src="https://qiita-image-store.s3.amazonaws.com/0/19692/799d24fd-8c25-436e-9199-3be3e2797d57.png" width="180" />&nbsp;<img src="https://qiita-image-store.s3.amazonaws.com/0/19692/ee222488-ccf1-4c80-1f4f-fb8e1ab55e04.png" width="180" />&nbsp;<img src="https://qiita-image-store.s3.amazonaws.com/0/19692/d46d8717-6e6c-190b-a5a7-13fa9d9ec67e.png" width="180" />

# デザインについて

## ダークモードの色について

> Android Deveopers スタイルとテーマ
> https://developer.android.com/guide/topics/ui/themes?hl=ja

Androidのテーマには大きく黒背景(Dark)と白背景(Light)があります。
コンポーネントごとに個別のカラー設定も可能ですが、
通常はThemeとしてカラーなどの表示をまとめて設定します。

```style.xml
<resources>
    <!-- styleでテーマを書いていきます -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" />
    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
</resources>

```

```AndroidManifest.xml
:
        <!-- android:themeで使用するテーマを指定します -->
        <activity
                android:name=".MainActivity"
                android:label="@string/app_name"
                android:theme="@style/AppTheme.NoActionBar">
:
```

Android Studioでプロジェクトを作成するとデフォルトとして`Theme.AppCompat.Light.DarkActionBar`が設定されています。
一切設定をしていない素の`Theme.AppCompat.Light` の画面キャプチャは以下となります。


```style.xml
<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light" />
</resources>
```

<img src="https://qiita-image-store.s3.amazonaws.com/0/19692/e571fc2d-52c7-db0c-e835-74ae91a1d4a6.png" width="240" />

```style.xml
<resources>
    <style name="AppTheme" parent="Theme.AppCompat" />
</resources>
```
<img src="https://qiita-image-store.s3.amazonaws.com/0/19692/1d2e8adc-7468-d5b5-e644-4d3c9a5370c9.png" width="240" />


上記の色はサポートライブラリの以下xmlが使用されています。

>  colors_material.xml
https://chromium.googlesource.com/android_tools/+/HEAD/sdk/extras/android/support/v7/appcompat/res/values/colors_material.xml

カラーコードを表にしてまとめると以下のようになります。
(xml上はARGBカラーコード表記ですが、QiitaにRGBカラーコード表示機能があるためA100%のものはRGBに省略しました)

||material_dark|material_light|
|:--|:--|:--|
|foreground|`#ffffff` (white)|`#000000` (black)|
|background|`#303030` (grey_850)|`#fafafa` (grey_50)|
|background_floating|`#424242` (grey_800)|`#ffffff` (white)|
|primary|`#212121` (grey_900)|`#f5f5f5` (grey_100)|
|primary_dark|`#000000` (black)|`#757575` (grey_600)|
|ripple|`#33ffffff`|`#1f000000`|
|accent|`#80cbc4` (deep_teal_200)|`#009688` (deep_teal_500)|
|button|`#5a595b`|`#d6d7d7`|
|primary_text_default|`#ffffffff`|`#de000000`|
|secondary_text_default|`#b3ffffff`|`#8a000000`|

> Material Design / The color system
> https://material.io/design/color/the-color-system.html

上記Material Designサイトでは表記されていないgrey_850なども使用されています。
Floating Action Buttonにも使用されているaccentカラーは
lightでは500ベース, darkでは200ベースがデフォルトのようです。

## ダークモードのアイコンについて

YouTubeやTwitterでアイコンが表示されていますが共通しているのは欠けた月をモチーフとしています。
YouTubeはMaterial Designの `brightness_4` を使用しています。
Twitterの右上が欠けた月はMaterial Designにないオリジナルのアイコンです。

> Material Design / Icons 
> https://material.io/tools/icons/

YouTubeのアイコン
<img width="307" alt="スクリーンショット 2019-01-20 23.57.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/4ee49abf-000a-e976-3246-68bda88ef194.png">

Twitterのアイコン
<img width="211" alt="スクリーンショット 2019-01-20 23.57.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/80cda253-71ff-f731-033c-6be4ceb3e11f.png">


私は個人のアプリでは `brightness_2` を使用しました。
Material Designサイトの以下のあたりがおすすめです。

↓このへん
<img width="1143" alt="スクリーンショット 2019-03-01 0.24.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/c43a6b0c-462a-3720-a9f4-6b7a3489cbef.png">


# 開発について

## 夜間モードリソースを使う実装方法がオススメ

Theme切り替えはいくつかの実装方法がありますが、「夜間モード」を用いると簡潔に行うことができます。
Androidでは2010年に公開されたAndroid2.2(v8)からカーナビアプリ・デスクトップ向けアプリ向けに、
夜のみDarkテーマを使用する「夜間モード」があります。


> リソースの提供 - 夜間モード
> https://developer.android.com/guide/topics/resources/providing-resources#NightQualifier

> Android Developers Documentation - UiModeManager
> https://developer.android.com/reference/android/app/UiModeManager#setNightMode(int)

リソース末尾に`-night`を付与することで昼間向けテーマと夜間向けテーマを設定することができます。

- res/values/themes.xml
- res/values-night/themes.xml

上記の「夜間モード」はAndroid6.0(v23)からモバイルアプリでも使用できるようになりました。
切替方法は後述します。

## DayNightテーマ

> Medium - Android Developers "AppCompat — DayNight"
> https://medium.com/androiddevelopers/appcompat-v23-2-daynight-d10f90c83e94

夜間モード切り替えは全体であれば`AppCompatDelegate.setDefaultNightMode()`特定のAppCompat内であれば`AppCompatDelegate.setLocalNightMode()`で行います。
Android9からは「システム設定に従う」が追加され、デフォルト設定になっています。

> AppCompatDelegate.setDefaultNightMode()
> 
> - MODE_NIGHT_NO. Always use the day (light) theme.
> - MODE_NIGHT_YES. Always use the night (dark) theme.
> - MODE_NIGHT_AUTO - !!Soon to be deprecated!!
> - MODE_NIGHT_FOLLOW_SYSTEM (default). This setting follows the system’s setting, which on Android Pie and above is a system setting (more on this below).

また、昼間であれば`Theme.AppCompat.Light`、夜であれば`Theme.AppCompat`を使用するDayNightテーマがサポートライブラリのv23から追加されています。

``` theme.xml
<style name="MyTheme" parent="Theme.AppCompat.DayNight">
</style>
```

ユーザが自発的に夜間モードテーマを切り替える場合、
切り替え後は `Activity#recreate()`を呼び出すとテーマが適応されます。

## 【補足】MaterialComponent.DayNightテーマ

> Medium - Android Developers "DayNight — Adding a dark mode to your app"
> https://medium.com/androiddevelopers/appcompat-v23-2-daynight-d10f90c83e94

ちょうどこの記事を書いていた2019年2月に上記のMediumが更新されました..!
タイトルもダークモード関連に変更..!

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">Just updated my (now 3 years old) blog post on AppCompat&#39;s DayNight support for dark themes ⚫⚪. It should now be up-to-date, and talks about a few changes coming out soon.<a href="https://t.co/dkGU7MTWvP">https://t.co/dkGU7MTWvP</a></p>&mdash; Chris Banes (@chrisbanes) <a href="https://twitter.com/chrisbanes/status/1098777812469669888?ref_src=twsrc%5Etfw">2019年2月22日</a></blockquote>

ざっくりと変更点は
`Theme.MaterialComponents.DayNight` が `1.1.0` から使える。
`AppCompatDelegate.setDefaultNightMode()`で`MODE_AUTO`は非推奨にする。
とのことです。


# 個人的な感想

実際に開発して画面を見比べてみて、ダークモード実装が映えるのは
値段の高い端末よりも安価なディスプレイを搭載した端末のように感じました。
Android Go端末やノングレア液晶のChromebookだと白背景よりも黒背景のほうが格段に見やすくなったように感じます。

個人的に、去年にダークモードがない理由でアプリに低レビューをいただいた事がありました。。
今年以降、ダークテーマがアプリの必須機能かのようになる可能性もあります。。

ダークモードの実装は容易ですが、Colorの整理に時間が取られました。
リソースの整理は日頃やっておくと良いかもしれません。

おわり。