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

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

onTap 内で新しい画面を開始しようとしていますが、次のエラーが発生します。

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

ナビゲートするために使用しているコードは次のとおりです。

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

次のようにアプリでルートを設定しました。

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

私は、stocks サンプル アプリケーションを使用してコードをコピーしようとしました。Navigator と Route のドキュメントを確認しましたが、コンテキストに Navigator を含める方法がわかりません。onTapcontextで使用されているものは、ビルド メソッドに渡されるパラメーターから参照されます。

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),
  );
 }
}

ベストアンサー1

要約: にアクセスする必要があるウィジェットNavigatorを にラップするBuilderか、そのサブツリーを クラスに抽出します。そして、 new を使用しBuildContextて にアクセスしますNavigator


このエラーは宛先とは無関係です。親としてcontextインスタンスを含まない を使用したために発生しますNavigator

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

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

待ってください、すでにMaterialApp/を持っていますWidgetsApp!

おそらくその通りです。ただし、 /contextの親である を使用すると、このエラーが依然として発生する可能性があります。MaterialAppWidgetsApp

Navigator.of(context)これは、 を実行すると、使用されている に関連付けられているウィジェットから開始され、 が見つかるか、反復処理するウィジェットがなくなるcontextまでウィジェット ツリー内を上方向に移動するためです。Navigator

最初のケースでは、すべて問題ありません。2番目のケースでは、

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

それで、どうすれば修正できるのでしょうか?

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

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は実際には の親であるということです。したがって、の には が親として存在しません。MaterialAppMaterialAppMyAppBuildContextMaterialApp

この問題を解決するには、別の を使用する必要があります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, "/"),
          ),
        ),
      ),
    );
  }
}

おすすめ記事