1. ホーム
  2. flutter

[解決済み] Navigatorを含まないコンテキストで要求されたNavigator操作

2022-07-13 15:03:39

質問

onTap内で新しい画面を起動しようとしているのですが、以下のエラーが発生します。

ナビゲータを含まないコンテキストでナビゲータ操作が要求されました。 ナビゲーターが含まれていないコンテキストでナビゲーター操作が要求されました。

私がナビゲートするために使っているコードは

onTap: () { Navigator.of(context).pushNamed('/settings'); },

私のアプリでは、以下のようにルートを設定しています。

routes: <String, WidgetBuilder>{
    '/settings': (BuildContext context) => new SettingsPage(),
},

株のサンプルアプリケーションを使って、コードをコピーしてみました。NavigatorとRouteのドキュメントを見ましたが、Navigatorを含むようにコンテキストを作ることができるのかが分かりません。そのため context は、ビルドメソッドに渡されたパラメータから参照されています。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

SettingsPageは以下のようなクラスです。

class SettingsPage extends Navigator {

Widget buildAppBar(BuildContext context) {
  return new AppBar(
    title: const Text('Settings')
  );
}

@override
Widget build(BuildContext context) {
  return new Scaffold(
    appBar: buildAppBar(context),
  );
 }
}

どのように解決するのですか?

TLDR : にアクセスする必要があるウィジェットをラップします。 Navigator にアクセスする必要があるウィジェットを Builder に変換するか、そのサブツリーをクラスに抽出します。そして、新しい BuildContext にアクセスするために Navigator .


このエラーは宛先とは関係ありません。このエラーは context を含んでいない Navigator インスタンスを親として含まない

では、Navigatorのインスタンスを作るにはどうすればいいのでしょうか?

これは通常、ウィジェットツリーに MaterialApp または WidgetApp . 手動で行うこともできますが Navigator を直接使うこともできますが、あまりお勧めしません。そうすると、そのようなウィジェットの子ウィジェットは、すべて NavigatorState を使って Navigator.of(context) .

待って、私はすでに MaterialApp / WidgetApp !

その可能性が高いです。しかし、このエラーはまだ context の親である MaterialApp / WidgetApp .

このようなことが起こるのは Navigator.of(context) に関連付けられたウィジェットから開始されるからです。 context に関連付けられたウィジェットから開始します。そして、ウィジェットツリーの上方にある Navigator が見つかるか、それ以上ウィジェットがなくなるまで、ウィジェットツリーを上方に移動します。

最初のケースでは、すべてがうまくいっています。2つ目の場合は

Navigatorを含まないコンテキストでNavigator操作が要求されました。

では、どのように修正すればいいのでしょうか?

まず、このエラーを再現してみましょう。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Center(
        child: RaisedButton(
          child: Text("Foo"),
          onPressed: () => Navigator.pushNamed(context, "/"),
        ),
      ),
    );
  }
}

この例では、クリックすると '/' に移動しようとしますが、代わりに例外を投げるボタンを作成します。

ここで注目すべきは

  onPressed: () => Navigator.pushNamed(context, "/"),

を使用しました。 context に渡され buildMyApp .

問題は MyApp の親であることです。 MaterialApp . をインスタンス化するのはウィジェットですから。 MaterialApp ! したがって MyApp 's BuildContext には MaterialApp を親として持っていません。

この問題を解決するために、別の context .

この場合、最も簡単な解決策は、新しいウィジェットを MaterialApp . そして、そのウィジェットのコンテキストを使って Navigator の呼び出しを行います。

これを実現するには、いくつかの方法があります。を抽出することができます。 home をカスタムクラスとして作成する。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHome()
    );
  }
}

class MyHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: RaisedButton(
          child: Text("Foo"),
          onPressed: () => Navigator.pushNamed(context, "/"),
        ),
      );
  }
}

あるいは Builder :

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(
        builder: (context) => Center(
              child: RaisedButton(
                child: Text("Foo"),
                onPressed: () => Navigator.pushNamed(context, "/"),
              ),
            ),
      ),
    );
  }
}