📏

【Flutter】Flutter Web でステータスバーの色をいい感じにする

2025/01/13に公開

概要

https://zudah228.dev

Flutter Web でサイト構築をした時に、iOS の Safari で上のステータスバーが背景の濃い紫ではなく、白くなってしまいました。

さっと解決したかったですが、Flutter の Issue や個人ブログにもクリティカルな解決策がありませんでした。
なので、独自のやり方で行った解決法を書き残しておきます。

変に難しいことしようとしなくても、解決はそんなに難しくなかったです。

解決策

方針として、index.html に固定値を渡すのではなく、Dart で完結して、さらに動的に変えれるようにすることを目指しました。

ステータスバーの色は html の meta タグの theme-color で決まってるっぽいので、そこを動的に変更することで実現します。

https://developer.mozilla.org/ja/docs/Web/HTML/Element/meta/name/theme-color

web パッケージ を利用して、直接 meta タグにカラーコードをセットするのをゴールにします。

追記

dart:html 使ってましたが、Koji さんのアドバイスで web パッケージに変更しました。
現在、dart:html は非推奨で WebAssembly に対応してないなど色々あるらしい(知らなかった)。

以下公式の解説
https://dart.dev/interop/js-interop/package-web#package-web-vs-dart-html

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 関数を用意しときます。

web_theme_color_adaptor.dart
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 を使います。

web_theme_color_adaptor.dart
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);
  }
}

これをどこかに設定すれば完了です。

main.dart
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 を追加するだけ。

main.dart
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(
    // ...
web_theme_color_adaptor.dart
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