はじめに
NativeScript(NativeScript-Vue)で Dark Mode(iOS), Dark Theme(Android) に対応する方法。
TL;DR
- Android:
forceDarkAllowed
で Dark Theme のサポート有無を設定
- iOS:
UIUserInterfaceStyle
で Dark Mode を非サポートに設定可能(デフォルトで影響を受ける)
- Dark Mode/Theme だと
.ns-dark
, Light だと .ns-light
が root-view に適用される
@nativescript/theme
を使って Theme.setMode(Theme.Light)
で強制変更もできる
目次
- はじめに
- TL;DR
- 環境・条件
- 詳細
- 前置き
- Android
- iOS
- テーマの強制指定
- iOS
- iOS, Android 共通
- ダークモード対応
- スタイル
- 現在の設定、設定変更の検出
- まとめ
- 参考文献
環境・条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| $ sw_vers ProductName: Mac OS X ProductVersion: 10.15.4 BuildVersion: 19E287
$ node -v v12.7.0
$ npm -v 6.10.3
$ tns --version 6.4.0
$ grep -C1 version package.json "tns-android": { "version": "6.4.1" }, "tns-ios": { "version": "6.4.2" }
$ tns plugin Dependencies: ┌───────────────────────────────┬─────────┐ │ Plugin │ Version │ │ @nativescript/theme │ ^2.2.1 │ │ @vue/devtools │ ^5.0.6 │ │ nativescript-socketio │ ^3.2.1 │ │ nativescript-toasty │ ^1.3.0 │ │ nativescript-vue │ ^2.4.0 │ │ nativescript-vue-devtools │ ^1.2.0 │ │ tns-core-modules │ ^6.0.0 │ │ vuex │ ^3.1.1 │ └───────────────────────────────┴─────────┘ Dev Dependencies: ┌────────────────────────────────────┬─────────┐ │ Plugin │ Version │ │ @babel/core │ ^7.0.0 │ │ @babel/preset-env │ ^7.0.0 │ │ babel-loader │ ^8.0.2 │ │ nativescript-dev-webpack │ ^1.0.0 │ │ nativescript-vue-template-compiler │ ^2.0.0 │ │ nativescript-worker-loader │ ~0.9.0 │ │ node-sass │ ^4.9.2 │ │ vue-loader │ ^15.4.0 │ └────────────────────────────────────┴─────────┘
|
詳細
Dark Mode - NativeScript Docs にまとまっている。
前置き
Android
参考: Dark Theme For Android
Android 10(API level 29) 以降で Dark Theme をサポート。
NativeScript v6.2 以降のバージョンで作られたアプリだと、/app/App_Recoures/Android/src/main/res/values/styles.xml
に forceDarkAllowed
の設定がデフォルトでされている。
1
| <item name="android:forceDarkAllowed">true</item>
|
※forceDarkAllowed
が無ければ Dark Theme の影響を受けない、というようにも読めるが詳細未確認。
iOS
参考: Dark Mode For iOS - Dark Mode - NativeScript Docs
NativeScript v6.2 より古いバージョンで作られたアプリだと Dark Mode の影響を受けない。
NativeScript v6.2 以降、Xcode 11 以上でビルド、iOS 13 以降だと Dark Mode の影響を受ける。
テーマの強制指定
iOS
参考: Dark Mode For iOS - Dark Mode - NativeScript Docs
ダークモードをオフにしたい(ひとまず非サポートにしたい)場合は app/App_Recoures/iOS/Info.plist
に UIUserInterfaceStyle
の設定を追加。
1 2 3 4 5 6 7 8 9
| ... <plist version="1.0"> <dict> ... + <key>UIUserInterfaceStyle</key> + <string>Light</string> ... </dict> </plist>
|
iOS, Android 共通
参考: ios - How to effectively disable Dark Mode theming in Nativescript? - Stack Overflow
以下コードを実行することで、テーマを強制指定できる。
1 2
| import Theme from "@nativescript/theme"; Theme.setMode(Theme.Light);
|
NativeScript-Vue の場合は app/main.js
で実行すれば良い。
1 2 3 4 5 6 7 8 9
| import Vue from 'nativescript-vue'
import Theme from "@nativescript/theme"; Theme.setMode(Theme.Light);
import App from './components/App' new Vue({ render: h => h('frame', [h(App)]) }).$start()
|
なお iOS は、前述の UIUserInterfaceStyle
を app/App_Recoures/iOS/Info.plist
に設定しておかないと、システム設定の Dark Mode 設定が優先される模様。
ダークモード対応
参考: How Does It Work
スタイル
Dark Mode だと .ns-dark
が、Light Mode だと .ns-light
が root-view に適用される。
以下のようにすると、後述の画像のようになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <template> <Page> <ActionBar title="Welcome to NativeScript-Vue!" /> <GridLayout columns="*" rows="*"> <Label class="message" text="Hello World!" col="0" row="0" /> </GridLayout> </Page> </template>
<style scoped lang="scss"> .message { vertical-align: center; text-align: center; font-size: 20; }
.ns-light { .message { color: #333333; }
ActionBar { background-color: #53ba82; color: #ffffff; } }
.ns-dark { .message { color: #ffffff; }
ActionBar { color: #ffffff; } } </style>
|
Light Mode
Dark Mode
現在の設定、設定変更の検出
また、systemAppearance や systemAppearanceChangedEvent イベントを使った処理もできる。
1 2 3 4 5 6 7 8 9 10 11
| import Vue from 'nativescript-vue'
const application = require("tns-core-modules/application"); application.on(application.systemAppearanceChangedEvent, (args) => { console.log({ on: 'systemAppearanceChangedEvent', args }); });
import App from './components/App' new Vue({ render: h => h('frame', [h(App)]) }).$start()
|
Android
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| { on: 'systemAppearanceChangedEvent', args: { eventName: 'systemAppearanceChanged', android: { constructor: [Object] }, newValue: 'light', // ***** object: { _observers: [Object], callbacks: [Object], _registeredReceivers: {}, _pendingReceiverRegistrations: [Object], nativeApp: [Object], packageName: 'com.jet.truckshop', context: [Object], startActivity: [Object], _orientation: 'portrait', _systemAppearance: 'light', foregroundActivity: [Object], paused: true } } }
{ on: 'systemAppearanceChangedEvent', args: { eventName: 'systemAppearanceChanged', android: { constructor: [Object] }, newValue: 'dark', // ***** object: { _observers: [Object], callbacks: [Object], _registeredReceivers: {}, _pendingReceiverRegistrations: [Object], nativeApp: [Object], packageName: 'com.jet.truckshop', context: [Object], startActivity: [Object], _orientation: 'portrait', _systemAppearance: 'dark', foregroundActivity: [Object], paused: true } } }
|
iOS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| { on: 'systemAppearanceChangedEvent', args: { eventName: 'systemAppearanceChanged', ios: { _backgroundColor: {}, _observers: [Object], _delegate: [Object], _window: {}, _orientation: 'portrait', _rootView: [Object], _systemAppearance: 'light' }, newValue: 'light', object: { _backgroundColor: {}, _observers: [Object], _delegate: [Object], _window: {}, _orientation: 'portrait', _rootView: [Object], _systemAppearance: 'light' } } }
{ on: 'systemAppearanceChangedEvent', args: { eventName: 'systemAppearanceChanged', ios: { _backgroundColor: {}, _observers: [Object], _delegate: [Object], _window: {}, _orientation: 'portrait', _rootView: [Object], _systemAppearance: 'dark' }, newValue: 'dark', object: { _backgroundColor: {}, _observers: [Object], _delegate: [Object], _window: {}, _orientation: 'portrait', _rootView: [Object], _systemAppearance: 'dark' } } }
|
まとめ
- Android:
forceDarkAllowed
で Dark Theme のサポート有無を設定
- iOS:
UIUserInterfaceStyle
で Dark Mode を非サポートに設定可能(デフォルトで影響を受ける)
- Dark Mode/Theme だと
.ns-dark
, Light だと .ns-light
が root-view に適用される
@nativescript/theme
を使って Theme.setMode(Theme.Light)
で強制変更もできる
参考文献
関連記事