Slide 1

Slide 1 text

©10X, Inc. All Rights Reserved. 1 
 本気でDarkModeに対応する
 みやけりょう @ryo_ryoo_ryooo
 Flutter Kaigi

Slide 2

Slide 2 text

©10X, Inc. All Rights Reserved. 2 Dark Mode って必要?
 ※ Android では Dark Theme っていいます

Slide 3

Slide 3 text

©10X, Inc. All Rights Reserved. 個人的には、なくてもいい
 3 ● 黒い画面怖い
 ● 実装が面倒
 ● 生鮮食品購入するのに暗いとかないわ
 
 (ネットスーパーの場合)

Slide 4

Slide 4 text

©10X, Inc. All Rights Reserved. どういうアプリでDarkModeが欲しい?
 4 ● エンジニアが使うエディタ
 ○ VS Code,Android Studio, IntelliJ IDEA
 ● 暗い部屋でだらだら見るアプリ
 ○ SNS,ニュース,Kindle,動画アプリはDarkModeだけでいい


Slide 5

Slide 5 text

©10X, Inc. All Rights Reserved. 5 Dark Mode って必要?
 必要です。
 DarkMode対応しましょう


Slide 6

Slide 6 text

©10X, Inc. All Rights Reserved. まずはテーマを用意しましょう 6 Darkテーマ ミニマムだとたったこれだけ Default が system なので省略可 普通のLightテーマ OSの設定で勝手に切り替わります

Slide 7

Slide 7 text

©10X, Inc. All Rights Reserved. 影響範囲が分かる範囲でテーマをカスタマイズします
 7 iconTheme, textTheme, appBarTheme, buttonTheme…
 テーマの名前から想像したり、各Widgetのソースコードを読んでみたりして、 「あぁ、このテーマがここに影響するのね。」みたいに言いながら設定するの がいいんじゃないですか。


Slide 8

Slide 8 text

©10X, Inc. All Rights Reserved. テーマだけで足りるか?
 8 
 タイトル,説明文,日付
 複数のテキスト複数のStyleがある場合どうする?
 
 TextThemeで使い分けるのがいい
 ● タイトル:textTheme.titleSmall
 ● 説明文:textTheme.bodyMedium
 ● 日付:textTheme.caption
 いけそう...


Slide 9

Slide 9 text

©10X, Inc. All Rights Reserved. やっぱりテーマだけでは足りない
 9 
 ● エラーメッセージはこの色ね
 ○ Lifghtは #EF5353 で DarkModeの場合は #FC7463 です
 ● Disableのときはこっちの色で
 ● 検索にマッチしてたら背景をハイライトカラーにして
 ● URLはリンクなのでこの色で
 ○ 一回踏んだリンクはこっちの色ね
 ● DarkModeのときはこっちのアイコンで
 ○ SVGで表現できなったからPNGにしたよ
 もう無理。頑張ったらギリギリできるかもしれんけど無理


Slide 10

Slide 10 text

©10X, Inc. All Rights Reserved. 独自のテーマクラスを作りましょう
 10 ● static で light と dark を定義するとよい
 ● Color以外にもAssetPathの文字列でも何でもOK
 ● extensionを作るとtextTheme等と同じような感じで使えます
 ● final oreTheme = Theme.of(context).oreTheme; ● Themeが切り替わると一緒にOreThemeも切り替わります
 これで終わりでもいいんだけど...

Slide 11

Slide 11 text

©10X, Inc. All Rights Reserved. ThemeExtensionって
 11 ● Flutter3からはThemeExtensionがつかえる
 ● Themeの中に独自のテーマクラスを加えられる
 ● ThemeData.extensionsに設定する
 
 ● final oreTheme = Theme.of(context).extension()!; で利用できる
 
 extensionsに設定 ※ThemeData.from では使えないのでここではcopyWithを使ってる

Slide 12

Slide 12 text

©10X, Inc. All Rights Reserved. ThemeExtensionって
 12 ● ThemeExtensionを継承する
 ● copyWith と lerp を実装する
 ● extensionを作るとtextTheme等と同じような感じで使えます
 ● final oreTheme = Theme.of(context).oreTheme; 
 copyWith と lerp ちょっと面倒

Slide 13

Slide 13 text

©10X, Inc. All Rights Reserved. アプリ内でModeを切り替えたい
 13 ● ThemeMode の設定画面を作る ● SharedPreferences 等に保存する ● ChangeNotifier 等で MaterialApp の themeMode を切り替える

Slide 14

Slide 14 text

©10X, Inc. All Rights Reserved. いまDarkModeなのかどうか
 14 OSの設定で決まるときは、 WidgetsBinding.instance.window.platformBrightness を使うとContextも不要で楽。

Slide 15

Slide 15 text

©10X, Inc. All Rights Reserved. 忘れがちな SystemUiOverlayStyle
 15 これが SystemNavigationBar 未指定だとLightのとき味気ない

Slide 16

Slide 16 text

©10X, Inc. All Rights Reserved. ジェスチャーだから3つボタンないよってときも
 16 これが SystemNavigationBar 未指定だとLightのとき味気ない

Slide 17

Slide 17 text

©10X, Inc. All Rights Reserved. SystemNavigationBarを透過したい
 17 ● SafeArea の bottom が Bar の高さだけ大きくなります。 
 ● 個人的には、3つボタンのときは透過するの好きじゃない 


Slide 18

Slide 18 text

©10X, Inc. All Rights Reserved. 3つボタンかどうかで透過するかどうかわける
 18 SystemUiOverlayStyle もわけるとOK 


Slide 19

Slide 19 text

©10X, Inc. All Rights Reserved. 3つボタンかどうかって?
 19 ● Flutter だけで調べる方法がわからなかった 
 ● Android の Resources から NavigationBar の高さを取得することはできる 
 ● これを density で割って40以上なら3つボタンとかでよさそう 
 ● コードは長いのでここに置いてます 
 https://github.com/miyakeryo/flutter_kaigi_2022 


Slide 20

Slide 20 text

©10X, Inc. All Rights Reserved. まとめ
 20 ● DarkMode 対応は我々にとって必要 
 ● OreThemeData を ThemeData の extension にするのが簡単 
 ● ThemeExtension はちょっと面倒なのでlerp省略が楽 
 ● Android の SystemNavigationBar にこだわり始めると大変 
 ● https://github.com/miyakeryo/flutter_kaigi_2022 


Slide 21

Slide 21 text

©10X, Inc. All Rights Reserved. 21 おわり