最近になってようやくダークテーマ関連に足を踏み入れたのでまとめてみようと思いました。
呼び方
・私も勘違いしていたのですが、Androidはダークモード・ライトモードではなくダークテーマ・ライトテーマと呼ぶそうですね。
参考:ダークテーマ
色分け
・ライトテーマ(デフォルト)は今まで通りvalues/colors.xmlに定義しておくとして、ダークテーマ用のものはどうすれば良いのでしょうか。答えは簡単で、values-night/colors.xmlを作成、その中に定義しておけばよさそうです。
ただし、ライトテーマ用のcolors.xmlに定義がないものをダークテーマ用のcolors.xmlに定義することはできないようです。あくまでオーバーライドです。
基準色
・themeとして設定。以下あたりでしょうか。
Theme.AppCompat
Theme.AppCompat.DayNight
Theme.MaterialComponents.DayNight
任意のタイミングでテーマを切り替える
・最近はアプリ毎にテーマを設定できることがありますね。そのような場合はアプリ内設定画面などに適当なラジオボタンなどを置いてユーザの入力を読み取り、変更&保持を行えばよさそうです。
保持しているものを該当ActivityのonCreateで実行すると再度onCreateが走ってしまうので、もっと前段でテーマは決めてしまうのがよいですね。
(また、各Activityで受け取ることもできるようです。参考:ダークテーマ 構成の変更)
切り替えなどを行うUtilクラスがあると便利そうですね。ざっくりサンプルですが。
object SampleThemeManager {
/**
* テーマを変更する(アプリ全体に反映).
* @param mode MODE_NIGHT_YES, MODE_NIGHT_NO, MODE_NIGHT_FOLLOW_SYSTEM
*/
fun changeTheme(mode: Int) {
// OS10以上の時だけ実行する
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return
}
// modeが妥当かのチェック処理
// 実際に変更する
AppCompatDelegate.setDefaultNightMode(mode)
// 設定された値を保持する処理
}
/**
* テーマを変更する(Activity単位で反映).
* @param appCompatDelegate activityのdelegateなど
* @param mode MODE_NIGHT_YES, MODE_NIGHT_NO, MODE_NIGHT_FOLLOW_SYSTEM
*/
fun changeTheme(appCompatDelegate: AppCompatDelegate, mode: Int) {
// OS10以上の時だけ実行する
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return
}
// modeが妥当かのチェック処理
// 実際に変更する
appCompatDelegate.localNightMode = mode
// 設定された値を保持する処理
}
/**
* ダークテーマかどうか.
* @param activity チェック対象
* @return trueならばダークテーマ
*/
fun isDarkTheme(activity: Activity): Boolean {
return activity.resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
}
}
上記にあるように、適用範囲によって使い分ける必要があります。
アプリケーション全体に適用する | Activityにだけ適用する |
---|---|
AppCompatDelegate.setDefaultNightMode() | appCompatDelegate.localNightMode |
最後に
ダークテーマはもはや無ければならないものになっているので、今後も知見を広げていきたいと思います。
リリース後の機能追加等でダークテーマを実装する場合はリソースの整理が大変になるので、できれば最初から要件には入れていきたいです。