Android
 Computer >> コンピューター >  >> トラブルシューティング >> Android

Androidアプリにダークテーマ(ナイトモード)を導入する方法

Androidアプリの開発そのものは比較的容易ですが、魅力的なUIを設計することは実際には難しい作業です。シンプルでありながら洗練されたUIを作りたい開発者のために、私たちは「ダメなUIにならないAndroidアプリUIデザインの方法」というガイドを執筆しました。その中でダークモード/ナイトモードテーマの追加について簡単に触れましたが、本記事ではその具体的な実装手順を詳しく解説します。

アプリにダーク/ナイトモードテーマを追加することは、ユーザーにとって多くのメリットがあります。バッテリー消費を抑えられるだけでなく、夜間でも目に優しい表示が可能になります。白背景に黒文字、あるいは明るい色を多用したUIは、特に夜間には目に大きな負担をかけます。一方、暗い背景に明るめの文字色を組み合わせれば、目へのストレスやダメージを大幅に軽減できます。こうした理由から、YouTubeやRedditなど多くの人気アプリがダークテーマを採用し始めています。Facebookも5月にダークモードの提供を約束していましたが、残念ながらまだ公開には至っていません。

Androidアプリに切り替え可能なダークモードを簡単に追加したい方は、ぜひこのガイドの手順に従ってみてください。途中で問題が発生した場合は、コメントでお知らせください!

XML属性の作成

まず、テーマを管理するためのXML属性ファイルを作成します。ライト・ダーク2種類のテーマ用にリソースセットをそれぞれAPKに含めるとAPKサイズが肥大化してしまいますが、このXML経由であればAndroidがネイティブに属性の色を変更できるため、はるかに効率的です。

アプリの「resources」フォルダ内に attrs.xml という名前のファイルを作成し、以下の行を追加します(これらはスタイル指定可能な属性です):

<declare-styleable name="CTAppTheme">
      <attr name="primaryTextColor" format="color"/>
      <attr name="secondaryTextColor" format="color"/>
      <attr name="dividerColor" format="color"/>
      <attr name="backgroundCardColor" format="color"/>
      <attr name="iconPlaceholder" format="integer"/>
</declare-styleable>

Lollipop以前はドローアブルに対して属性を直接指定できず、リソースIDを指定する必要がありましたが、現在ではその制限はありません。

スタイルの追加

この仕組みを機能させるには、同じベースを共有する2つの個別のスタイルを作成する必要があります。1つ目はプライマリとなる「ライト」テーマ、2つ目は「ダーク」テーマです。

<!-- ライト用ベースアクティビティテーマ -->
<style name="ActivityTheme.Primary.Base.Light" parent="Theme.AppCompat.NoActionBar">
    <item name="primaryTextColor">#F4F4F6</item>
    <item name="secondaryTextColor">#96F4F4F6</item>
    <item name="backgroundCardColor">#FFFF</item>
    <item name="dividerColor">#F2F2F3</item>
    <item name="iconPlaceholder">@drawable/i_light_plholder</item>
</style>

<!-- ダーク用ベースアクティビティテーマ -->
<style name="ActivityTheme.Primary.Base.Dark" parent="Theme.AppCompat.NoActionBar">
    <item name="primaryTextColor">#33343B</item>
    <item name="secondaryTextColor">#8033343B</item>
    <item name="backgroundCardColor">#28292e</item>
    <item name="dividerColor">#F2F2F3</item>
    <item name="iconPlaceholder">@drawable/i_dark_pholder</item>
</style>

続いて、特定のアクティビティに対する実際のスタイルは以下のようになります:

<!-- Feedアクティビティ専用テーマ -->
<style name="FeedActivityThemeLight" parent="ActivityTheme.Primary.Base.Light">
    <item name="android:windowBackground">#F4F4F6</item>
</style>

<style name="FeedActivityThemeDark" parent="ActivityTheme.Primary.Base.Dark">
    <item name="android:windowBackground">#33343B</item>
</style>

これらのテーマのいずれかを、対象のアクティビティ(この場合はFeedActivity)のManifestファイル内で指定する必要があります。

ビューのスタイリング

以下はビューをスタイリングする具体例です。この例では「ページが見つかりません」というリダイレクトエラー画面向けのレイアウトを想定しています。

<ImageView
           android:id="@+id/placeHolderAssetImageView"
           android:layout_width="100dp"
           android:layout_height="100dp"
           android:src="?attr/iconPlaceholder"
           android:layout_marginBottom="8dp" />

       <TextView
           android:id="@+id/placeHolderTitleTextView"
           android:text="Page not found."
           android:textSize="16dp"
           android:textColor="?attr/primaryTextColor"
           android:layout_margin="16dp" />

動的なテーマ切り替えを有効にする方法

動的なテーマ切り替えを最も効率的に実現する方法は、設定値を保存しているSharedPreferencesの値を、Singletonパターンを利用してApplicationインスタンスに読み込んでおくことです。これにより、各アクティビティの開始時に毎回読み込む必要がなくなります。

public class App extends Application {
 public static final String TAG = "App";

private boolean isNightModeEnabled = false;

@Override
 public void onCreate() {
 super.onCreate();

// ここでナイトモードの状態を読み込む
 SharedPreferences mPrefs =  PreferenceManager.getDefaultSharedPreferences(this);
 this.isNightModeEnabled = mPrefs.getBoolean("NIGHT_MODE", false);
 }

public boolean isNightModeEnabled() {
 return isNightModeEnabled;
 }

public void setIsNightModeEnabled(boolean isNightModeEnabled) {
 this.isNightModeEnabled = isNightModeEnabled;
 }
}

このインスタンスは他のどのコンポーネントよりも先に起動されるため、アプリが開かれた後は、アプリに属する任意のアクティビティからいつでも isNightModeEnabled() のブール値を呼び出せるようになります。

public final class FeedActivity extends AppCompatActivity {
 private final static String TAG = "FeedActivity";

@Override
 protected void onCreate(Bundle savedInstanceState) {
    if (MyApplication.getInstance().isNightModeEnabled()) {
       setTheme(R.style.FeedActivityThemeDark);
    }
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_feed);
 }
}

ただし注意点として、Manifestファイルで指定されたテーマとは異なるテーマを適用したい場合は、必ず親クラスのonCreate()メソッドを呼び出す前に処理を行う必要があります。

AppCompatを使用した状態の設定

AppCompatは幅広い場面で非常に便利なライブラリですが、ここではモード状態の設定に使用します。この方法を使えば、キャッシュ済みの状態を保持するためにアプリインスタンスを利用する必要がなくなり、アプリキャッシュの肥大化もわずかながら抑えられます。

AppCompatDelegate
.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);

ここで指定できるのは以下のいずれかです:

  • AppCompatDelegate.MODE_NIGHT_YES
  • AppCompatDelegate.MODE_NIGHT_NO
  • AppCompatDelegate.MODE_NIGHT_AUTO

状態の取得

AppCompatDelegate.getDefaultNightMode();

public final class FeedActivity extends AppCompatActivity {
 private final static String TAG = "FeedActivity";

@Override
 protected void onCreate(Bundle savedInstanceState) {
   if (AppCompatDelegate.getDefaultNightMode()
   ==AppCompatDelegate.MODE_NIGHT_YES) {
      setTheme(R.style.FeedActivityThemeDark);
   }
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_feed);
 }
}

以上で実装は完了です。あとは好みに応じてカラーや値を自由にカスタマイズできます。このガイドは、Androidアプリにネイティブなダークテーマを組み込むための第一歩として、きっと役立つはずです。

  1. お住まいの国で配信されていないAndroidアプリをダウンロードする3つの方法

    Androidの大きな魅力のひとつは、プラットフォーム上に存在する膨大な数のアプリです。しかし、その豊富な選択肢の中には、特定の国や地域でのみリリースされているアプリも少なくありません。「海外限定のあのアプリを使いたい」という方は、本記事で紹介する「お住まいの国では配信されていないAndroidアプリをダウンロードする方法」をぜひチェックしてみてください。 なぜアプリには地域制限があるのか? 多くのアプリは地域限定で提供されており、特定のエリアでしか利用できません。その主な理由は以下のとおりです。 規制や法律による制限:アプリが提供するサービスが、その国では法的に認められていないケース。例え

  2. Androidで大切な写真を非表示にする方法|「Keep Photos Secret」で写真・動画をしっかり保護

    スマホの中には、人に見られたくない写真や動画がありませんか?家族や友人にスマホを渡したとき、勝手にギャラリーを見られるのが不安…そんな経験は誰にでもあるものです。実は、Androidスマートフォンなら専用アプリを1つ入れるだけで、大切な思い出を簡単に隠せます。この記事では、無料アプリ「Keep Photos Secret」を使ってAndroidの写真を非表示にする方法を詳しく解説します。 写真を秘密に:「Keep Photos Secret」でギャラリーの画像・動画をロック 最近見つけた便利なアプリのひとつが、Systweak Softwareが開発した「Keep Photos Secret」