Support Library の AppCompat 23.2.0 で、DayNight テーマが導入されました。これは、日中と夜間で異なるテーマ(日中は Light テーマ、夜間は Dark テーマ)を使い分けるときに使用します。ただし、単純にstyles.xml
等のテーマの宣言で DayNight テーマを継承するだけでは使用できないので、以下に手順を書いておきます。
DayNight テーマを継承したテーマを作る
まずは DayNight テーマを継承しましょう。
<resources>
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
</style>
</resources>
リソースディレクトリを分ける
リソースディレクトリの修飾子として、notnight
とnight
が用意されています。それぞれ、日中用と夜間用のリソースを保管することになります。
- res
- values-night
- values-notnight
- values
- drawable-night
- drawable
notnight
が無い場合の日中用のリソースは修飾子がないものから取り出されます。
Application
クラスを継承する
Light テーマと Dark テーマを使い分ける判断は Support Library が行います。基本的には、アプリケーションのプロセスが生きている間は同じテーマが使用されます。アプリケーションのプロセスが立ち上がった時に、アプリが期待する判断の仕方をライブラリ側に伝達する必要が有るため、Application
クラスを以下のように継承して、static
初期化ブロックを使って実装します。
public class DayNightApplication extends Application {
static {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
}
}
合わせて、AndroidManifest.xml
も変更しておきましょう。
<manifest
package="com.sample.daynight"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:icon="@mipmap/ic_launcher"
android:name=".DayNightApplication"
android:label="@string/app_name"
android:theme="@style/AppTheme">
</application>
</manifest>
AppCompatDelegate
には、MODE_NIGHT_AUTO
以外に以下のような定数が宣言されています。それぞれ、役割とともに表に示します。
定数名 | 役割 |
---|---|
MODE_NIGHT_AUTO |
自動で判別する。リソースは日中の場合notnight 修飾子の付いたものを、夜間の場合はnight 修飾子の付いたものを使用する。 |
MODE_NIGHT_YES |
常に夜モードを使用する。リソースはnight 修飾子の付いたものを使用する。 |
MODE_NIGHT_NO |
夜モードは使用しない。リソースはnotnight 修飾子の付いたものを使用する。 |
MODE_NIGHT_FOLLOW_SYSTEM |
システムの判断に従って判別する。 |
(Optional) パーミッションを追加する
夜も安心、目に優しい UI を作ろうという記事でも言及していますが、日中か夜間かを判別するためには、日付・日時以外に位置情報が必要です。位置情報を得るパーミッションがない場合は、ハードコードされたおおよその時間が使用されます。より正確な日中・夜間の計算が必要な場合には、位置情報を得るパーミッションを取得します。
<manifest
package="com.sample.daynight"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- ... -->
</manifest>
実装例
例えば、colors.xml と styles.xml を以下のように定義してみましょう。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="background">#FFFFFF</color>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="background">#333333</color>
<color name="colorPrimary">#303F9F</color>
<color name="colorPrimaryDark">#242f78</color>
<color name="colorAccent">#a32751</color>
</resources>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="android:windowBackground">@color/background</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
この結果、画面は以下のようになります。
日中 | 夜間 |
---|---|
まとめ
この実装がうまくはまれば、夜も安心、目に優しい UI を作ろうの記事で紹介した日の出日の入りの計算を自分たちでしなくてもよくなります。また、Java のソースコード内で日中と夜間の分岐をすることなく、リソースによって区別ができるようになります。