SupportLibrary rev.23.2 で導入された DayNight テーマを使おう

  • 29
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Support Library の AppCompat 23.2.0 で、DayNight テーマが導入されました。これは、日中と夜間で異なるテーマ(日中は Light テーマ、夜間は Dark テーマ)を使い分けるときに使用します。ただし、単純にstyles.xml等のテーマの宣言で DayNight テーマを継承するだけでは使用できないので、以下に手順を書いておきます。

DayNight テーマを継承したテーマを作る

まずは DayNight テーマを継承しましょう。

styles.xml
<resources>
  <style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
  </style>
</resources>

リソースディレクトリを分ける

リソースディレクトリの修飾子として、notnightnightが用意されています。それぞれ、日中用と夜間用のリソースを保管することになります。

- res
  - values-night
  - values-notnight
  - values
  - drawable-night
  - drawable

notnightが無い場合の日中用のリソースは修飾子がないものから取り出されます。

Application クラスを継承する

Light テーマと Dark テーマを使い分ける判断は Support Library が行います。基本的には、アプリケーションのプロセスが生きている間は同じテーマが使用されます。アプリケーションのプロセスが立ち上がった時に、アプリが期待する判断の仕方をライブラリ側に伝達する必要が有るため、Applicationクラスを以下のように継承して、static初期化ブロックを使って実装します。

DayNightApplication.java
public class DayNightApplication extends Application {
  static {
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
  }
}

合わせて、AndroidManifest.xmlも変更しておきましょう。

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 を作ろうという記事でも言及していますが、日中か夜間かを判別するためには、日付・日時以外に位置情報が必要です。位置情報を得るパーミッションがない場合は、ハードコードされたおおよその時間が使用されます。より正確な日中・夜間の計算が必要な場合には、位置情報を得るパーミッションを取得します。

AndroidManifest.xml
<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 を以下のように定義してみましょう。

values/colros.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>
values-night/colors.xml
<?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>
values/styles.xml
<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 のソースコード内で日中と夜間の分岐をすることなく、リソースによって区別ができるようになります。