1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter】MediaQueryを使ったらgo_routerが無限リダイレクト?その原因と回避方法

Posted at

Flutterで go_router を使っているとき、iOSでキーボードを表示すると無限リダイレクトが発生する現象に遭遇しました。

この記事ではその原因と、どのように解決したかを共有します!

🔥 問題の現象

theme: ThemeData(
  navigationBarTheme: NavigationBarThemeData(
    height: MediaQuery.of(context).size.height * 0.07,
  ),
),

このように MediaQueryThemeData 内で使用していたところ、

  • iOSでキーボードを開いた瞬間
  • go_routerredirect: が毎回実行される
  • 無限にリダイレクトが走り、ルーティングが止まる

という現象が発生しました。

🧠 なぜ起きたのか?

原因は「MediaQueryによるbuildの再実行」でした。

Flutterでは、MediaQuery, Theme, Directionality などの「InheritedWidget」に依存している場合、
その値が変わると自動的にWidgetツリーが再構築されます

MediaQuery はキーボード表示・非表示などで sizeviewInsets が変化するため、
build() が再実行されるトリガーになります。

そして、MaterialApp.router() の中で GoRouter(...) を初期化していたため、
redirect: が毎回再評価 → 状況によっては無限ループが起こっていたわけです。

🛠 解決策:再構築の影響を最小限に抑える

✅ 解決策1:MediaQueryの使用箇所を下層に移す

MediaQueryThemeDataやGoRouterの初期化部分では使わず
実際に必要なWidget内で使うようにしましょう。

NavigationBar(
  height: MediaQuery.of(context).size.height * 0.07,
)

→ こうすれば、キーボードなどによる画面サイズの変化が発生しても、
NavigationBarだけが再構築され、GoRouterThemeData には影響しません。


✅ 解決策2:MediaQueryの値をキャッシュする

初回だけMediaQueryのサイズを取得して保存しておけば、
再構築のたびに毎回取得し直す必要はありません。

double? _screenHeight;

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  _screenHeight ??= MediaQuery.of(context).size.height;
}

✅ 解決策3:再構築を検知して明示的に制御する

Flutterの WidgetsBindingObserver を使えば、
画面サイズやキーボード表示の変化をイベントとして検知できます。

class _MyState extends State<MyPage> with WidgetsBindingObserver {
  double _keyboardHeight = 0;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeMetrics() {
    final bottomInset = WidgetsBinding.instance.window.viewInsets.bottom;
    setState(() {
      _keyboardHeight = bottomInset;
    });
  }
}

✅ まとめ

ポイント 説明
MediaQueryはInheritedWidget 値が変わると依存Widgetのbuild()が再実行される
GoRouterなどの初期化に影響を与えると危険 redirect: が毎回評価され無限ループになる
MediaQueryは必要な場所で、必要なタイミングだけ使おう これが一番の安定策!

💬 おわりに

レスポンシブ対応のために MediaQuery を使うのは正しいアプローチです。
ただし、それを「どこで使うか」で挙動が大きく変わる点には注意が必要!

同じようなハマりポイントに遭遇した方の参考になれば幸いです 🙌


🧑‍💻 ご質問やご意見があれば、コメントでお気軽にどうぞ!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?