Help us understand the problem. What is going on with this article?

React Native製の公開しているアプリにダークモードを実装してみた

More than 1 year has passed since last update.

以前Qiitaで紹介したアプリペペロミアにダークモードを実装してみたので、実装方法について紹介します。

■ React Native製、予定作成アプリ「ペペロミア」を公開しました
https://qiita.com/wheatandcat/items/3324dfd141729e46009f

対象のアプリ: ペペロミア

■ アプリ公式サイト
https://peperomia.app/

スクリーンショット 2019-09-20 00.02.05.png

GitHub

■ Peperomia
https://github.com/wheatandcat/Peperomia

環境

  • Expo SDK 34

実装してみた

動画にまとめました。

対象のpull request

■ ダークモードを実装する
https://github.com/wheatandcat/Peperomia/pull/108

実装方法

デザイン面

カラーを黒ベースに変えていきました。通常時とダークモード時を並べると、こんな感じです。

通常画面.png

ダークモード画面.png

カラー定義

以下のカラー設定を決めて各要素に設定

■ PeperomiaNative/src/config/theme.ts
https://github.com/wheatandcat/Peperomia/blob/e9a4beac729938b6f88366324dbb8873144736b7/PeperomiaNative/src/config/theme.ts#L149-L163

要素名 通常 Darkモード
バックグラウンド white black
バックグラウンド(サブ) lightGray darkGray
テキスト black lightGray
テキスト(サブ) darkGray gray
アイコン black lightGray
チップ lightGray darkGray
チップテキスト black gray
ヘッダーバックグラウンド Green black
タブバーバックグラウンド lightGray darkGray

基本的には上記の要素のみカラーを変更して、それ以外は通常時とダークモードでカラーに差分は無いようしました。

画像の変更

例えば下のような画面を単純にカラー定義に当てはめると。。。
アイコン画面.png

こんな感じになり画像と背景色が、かぶって画像が見えづらくなりました。
Simulator Screen Shot - iPhone X - 2019-09-20 at 20.06.47.png

なので色を反転した画像を用意して、こんな感じになりました。(+ステータスバーのカラーも変えました)
Simulator Screen Shot - iPhone X - 2019-09-20 at 20.16.55.png

これで良さ気です。

コード面

react-native-extended-stylesheetを使う

一般的にReactNativeのstyleの宣言はStyleSheetを使用すると思います。

https://facebook.github.io/react-native/docs/stylesheet

StyleSheetは最初にstyleを宣言してしまうので、あとから変数でカラーの値を変更しても値は動的に変更されません。
なので、StyleSheetのラッパーであるreact-native-extended-stylesheetを使用してカラー設定をしていきます。

■ react-native-extended-stylesheet
https://github.com/vitalets/react-native-extended-stylesheet

こちらのライブラリは最初にカラー定義を設定して

import EStyleSheet from "react-native-extended-stylesheet";

const setLight = () => {
  EStyleSheet.build({
    $theme: "light",
    $background: "#fff",
    $text: "#333631"
  });
}

const setDark = () => {
  EStyleSheet.build({
    $theme: "dark",
    $background: "#333631",
    $text: "#fff"
  });
}

以下のようにstyleを指定します。

import React from "react";
import { View, Text } from "react-native";
import EStyleSheet from "react-native-extended-stylesheet";

export default () => (
  <View style={styles.root}>
    <Text style={styles.text}>テスト</Text>
  </View>
)

const styles = EStyleSheet.create({
  root: {
    height: "100%",
    backgroundColor: "$background", // ← EStyleSheet.buildで定義した変数
  },
  text: {
    color: "$text", // ← EStyleSheet.buildで定義した変数
  }
});

あとは、以下のメソッドを実行すれば通常(Light)モード

setLight()

以下のメソッドを実行すればダークモードとstyle内のカラー変更が可能になります。

setDark()

・・・と言いたいところですが、これだけでは完全には変わりません。

以下のドキュメントに記載している通り、一度レンダリングされてしまったコンポーネントに関してはEStyleSheet.buildを実行してもstyleの変更はされません。値が適応されるのは再レンダリングのタイミングです。

■ react-native-extended-stylesheetの反映タイミング
https://github.com/vitalets/react-native-extended-stylesheet#theming

なので、ドキュメントの通り一旦render部分をnullにして、再レンダリングをさせる必要があります。
ペペロミアでは、Providerでカラー設定の制御を持ち、一旦アプリケーションのレンダリングをnullにしてから再レンダリングする実装でダークモードを実現しています。

■ PeperomiaNative/src/containers/Theme.tsx (カラー設定を制御するProvider)
https://github.com/wheatandcat/Peperomia/blob/d1c9308e9ec2a27ca7cbd3afc865652106fcf784/PeperomiaNative/src/containers/Theme.tsx

ここまで実装すればダークモード完成です。

その他の使えそうな設定

今回は使用していませんが、各ライブラリにThemeの設定が存在するので、この辺を利用するともっと良い感じに実装できるかもしれません。

■ React Navigation Theme設定
https://reactnavigation.org/docs/en/themes.html

■ React Native Elements ThemeProvider設定
https://react-native-training.github.io/react-native-elements/docs/customization.html#using-themeprovider

まとめ

最初は1日くらいで出来るだろうと思いましたが、stylesheetで結構ハマって結局3日くらいかかってしまいました。
一応ネタのため実装してみましたが、正直まだReact Nativeでダークモードを実装するのは時期尚早な気がします。

iOS13とAndroid10のリリースで両方ともダークモードが実装され需用が高まるはずなので、もっと良い実装方法が増えそうな気がするので、今は待ったほうが良いかなーと実装して思いました。
(再レンダリングを明示的に書かなくてはいけないのは、余り良い実装な気もしないので。。。)

Expoでダークモードを使ってみる

まだダークモード搭載のアプリはリリースはしていませんが、Expoにはデプロイしているので以下から実機で起動すること可能です。

https://expo.io/@wheatandcat/peperomia

wheatandcat
メインはReact-Native、NuxtJS、Golangとかやってます https://www.wheatandcat.me/
https://www.wheatandcat.me/
sharefull
短期間・短時間の仕事に特化したオンデマンドマッチングプラットフォーム「シェアフル」を開発中の、パーソルグループとランサーズの合弁会社
https://sharefull.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away