【Flutter】Flutter Web でステータスバーの色をいい感じにする
概要
Flutter Web でサイト構築をした時に、iOS の Safari で上のステータスバーが背景の濃い紫ではなく、白くなってしまいました。
さっと解決したかったですが、Flutter の Issue や個人ブログにもクリティカルな解決策がありませんでした。
なので、独自のやり方で行った解決法を書き残しておきます。
変に難しいことしようとしなくても、解決はそんなに難しくなかったです。
解決策
方針として、index.html
に固定値を渡すのではなく、Dart で完結して、さらに動的に変えれるようにすることを目指しました。
ステータスバーの色は html の meta タグの theme-color
で決まってるっぽいので、そこを動的に変更することで実現します。
web パッケージ
を利用して、直接 meta タグにカラーコードをセットするのをゴールにします。
追記
import 'package:web/web.dart' as web;
void _applyStatusBarColor(Color color) {
final String colorCode = color.code;
web.document
.querySelector("meta[name='theme-color']")
?.setAttribute("content", "#${colorCode}");
}
手順
特にウィジェットは使わないので、mixin で設定します。
meta タグを設定する _applyStatusBarColor
関数を用意しときます。
import 'package:web/web.dart' as web;
import 'package:flutter/material.dart';
mixin WebThemeColorAdaptor<T extends StatefulWidget> on State<T> {
void _applyStatusBarColor(Color color) {
web.document
.querySelector("meta[name='theme-color']")
?.setAttribute("content", "#${color.code}");
}
目標としては動的に、Theme.of(context)
から設定したいので didChangeDependencies
を使います。
import 'package:web/web.dart' as web;
import 'package:flutter/material.dart';
mixin WebThemeColorAdaptor<T extends StatefulWidget> on State<T> {
void _applyStatusBarColor(Color color) {
web.document
.querySelector("meta[name='theme-color']")
?.setAttribute("content", "#${color.code}");
}
// ここは好きな色で
+ Color _getEffectiveStatusBarColor(BuildContext context) {
+ final themeData = Theme.of(context);
+
+ return themeData.navigationBarTheme.backgroundColor ?? themeData.colorScheme.surfaceContainer;
+ }
+
+ void didChangeDependencies() {
+ final Color color = _getEffectiveStatusBarColor(context);
+
+ _applyStatusBarColor(color);
+ super.didChangeDependencies();
+ }
HTML のタグに埋め込むには、Color
をカラーコード文字列に変更する必要があります。
カラーコードは、r, g, b のそれぞれの値を 16 進数にしたものを並べたもので構成されています(参考)。
それに加え、Flutter 3.27 での変更(リンク)を反映して、文字列変更のための extension を実装します。
👇 コピペで使えます。
extension _HexColor on Color {
String get code => _floatToHexCode(r) + _floatToHexCode(g) + _floatToHexCode(b);
String _floatToHexCode(double x) {
return ((x * 255.0).round() & 0xff).toRadixString(16);
}
}
これをどこかに設定すれば完了です。
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
State<MyApp> createState() => MyAppState();
}
class MyAppState extends State<MyApp>
+ with WebThemeColorAdaptor {
Widget build(BuildContext context) {
return MaterialApp.router(
// ...
終わり!
ページ上部 | 少しスクロール |
---|---|
![]() |
![]() |
テーマから取得してるので、ライトモードにも対応
完成品まとめ
どこかに with WebThemeColorAdaptor
を追加するだけ。
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
State<MyApp> createState() => MyAppState();
}
class MyAppState extends State<MyApp>
+ with WebThemeColorAdaptor {
Widget build(BuildContext context) {
return MaterialApp.router(
// ...
import 'package:web/web.dart' as web;
import 'package:flutter/material.dart';
mixin WebThemeColorAdaptor<T extends StatefulWidget> on State<T> {
static void _applyStatusBarColor(Color color) {
web.document
.querySelector("meta[name='theme-color']")
?.setAttribute("content", "#${color.code}");
}
// ここは設定したい色を自由に
Color _getEffectiveStatusBarColor(BuildContext context) {
final themeData = Theme.of(context);
return themeData.navigationBarTheme.backgroundColor ?? themeData.colorScheme.surfaceContainer;
}
void didChangeDependencies() {
final Color color = getStatusBarColor(context);
_applyStatusBarColor(color);
super.didChangeDependencies();
}
}
extension _HexColor on Color {
String get code =>
_floatToHexCode(r) + _floatToHexCode(g) + _floatToHexCode(b);
String _floatToHexCode(double x) {
return ((x * 255.0).round() & 0xff).toRadixString(16);
}
}
Discussion