Fonctionnement du navigateur demandé avec un contexte qui ne comprend pas un navigateur

j'essaie de démarrer un nouvel écran dans un onTap mais j'obtiens l'erreur suivante:

navigation demandée avec un contexte qui ne comprend pas Navigator.

le code que j'utilise pour naviguer est:

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

j'ai mis en place une route dans mon application comme suit:

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

j'ai essayé de copier le code en utilisant l'application stock sample. J'ai j'ai regardé la documentation du navigateur et de la Route et je ne vois pas comment le contexte peut être fait pour inclure un navigateur. Le context utilisé dans l'onTap est référencé à partir du paramètre passé dans la méthode de construction:

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

SettingsPage est une classe comme suit:

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),
  );
 }
}
5
demandé sur juliusspencer 2017-05-16 17:35:51

3 réponses

j'ai mis en place cet exemple simple pour le routage dans une application de flutter:

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new MyHomePage(),
      routes: <String, WidgetBuilder>{
        '/settings': (BuildContext context) => new SettingsPage(),
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('TestProject'),
      ),
      body: new Center(
        child: new FlatButton(
          child: const Text('Go to Settings'),
          onPressed: () => Navigator.of(context).pushNamed('/settings')
        )
      )
    );
  }
}

class SettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('SettingsPage'),
        ),
        body: new Center(
            child: new Text('Settings')
        )
    );
  }
}

Note, que la page Settling étend StatelessWidget et non Navigator. Je ne peux pas reproduire votre erreur.

cet exemple vous aide-t-il à construire votre application? Laissez-moi savoir si je peux vous aider avec quoi que ce soit d'autre.

6
répondu Rainer Wittmann 2017-05-16 15:06:58

cette erreur n'est pas liée à la destination. Cela se produit parce que vous avez utilisé un context qui ne contient pas d'instance Navigator comme parent.

comment créer une instance Navigator alors ?

ceci est habituellement fait en insérant dans votre arbre à widget un MaterialApp ou WidgetApp . Bien que vous pouvez le faire manuellement en utilisant Navigator directement mais moins recommandé. Ensuite, tous les enfants d'un tel widget peut accéder à NavigatorState en utilisant Navigator.of(context) .

attendez, j'ai déjà un MaterialApp / WidgetApp !

C'est très probablement le cas. Mais cette erreur peut encore se produire lorsque vous utilisez un context qui est un parent de MaterialApp / WidgetApp .

cela se produit parce que lorsque vous faites Navigator.of(context) , cela va commencer à partir du widget associé au context utilisé. Et puis aller vers le haut dans le widget tree jusqu'à ce qu'il trouve un Navigator ou il n'y a plus de widget.

dans le premier cas, tout va bien. Dans la seconde, il lance un

Navigator opération demandée avec un contexte qui ne comprennent pas un Navigateur.

alors, comment puis-je le réparer ?

d'abord, reproduisons cette erreur:

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

cet exemple crée un bouton qui tente d'aller à '/' sur le clic mais lancera à la place une exception.

notez ici que dans le

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

nous avons utilisé context passé à build de MyApp .

le problème est, MyApp est en fait un parent de MaterialApp . Comme c'est le widget qui instancie MaterialApp ! Par conséquent, MyApp 's BuildContext n'a pas un MaterialApp en tant que parent!

Pour résoudre ce problème, nous avons besoin d'utiliser un autre context .

dans cette situation, la solution la plus simple est d'introduire un nouveau widget comme enfant de MaterialApp . Puis utilisez le contexte de ce widget pour faire l'appel Navigator .

il y a plusieurs façons d'y parvenir. Vous pouvez extraire home dans une classe personnalisée :

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

Ou vous pouvez utiliser 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, "/"),
              ),
            ),
      ),
    );
  }
}
6
répondu Rémi Rousselet 2018-07-11 19:07:27

une solution complète et éprouvée:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:my-app/view/main-view.dart';

class SplashView extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: Builder(
          builder: (context) => new _SplashContent(),
        ),
        routes: <String, WidgetBuilder>{
          '/main': (BuildContext context) => new MainView()}
    );
  }
}

class _SplashContent extends StatefulWidget{

  @override
  _SplashContentState createState() => new _SplashContentState();
}

class _SplashContentState extends State<_SplashContent>
    with SingleTickerProviderStateMixin {

  var _iconAnimationController;
  var _iconAnimation;

  startTimeout() async {
    var duration = const Duration(seconds: 3);
    return new Timer(duration, handleTimeout);
  }

  void handleTimeout() {
    Navigator.pushReplacementNamed(context, "/main");
  }

  @override
  void initState() {
    super.initState();

    _iconAnimationController = new AnimationController(
        vsync: this, duration: new Duration(milliseconds: 2000));

    _iconAnimation = new CurvedAnimation(
        parent: _iconAnimationController, curve: Curves.easeIn);
    _iconAnimation.addListener(() => this.setState(() {}));

    _iconAnimationController.forward();

    startTimeout();
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
        child: new Image(
          image: new AssetImage("images/logo.png"),
          width: _iconAnimation.value * 100,
          height: _iconAnimation.value * 100,
        )
    );
  }
}
0
répondu GiBi 2018-08-18 03:46:37