web-dev-qa-db-fra.com

Rediriger Flutter vers une page sur initState

J'ai une application où vous devez vous connecter pour continuer (par exemple avec Google).

Je souhaite rediriger l'utilisateur lorsque l'authentification est nécessaire.

Cependant, lorsque j'exécute une Navigator.of(context).pushNamed("myroute"). J'ai eu l'erreur suivante:

 ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 5624): The following assertion was thrown building _ModalScopeStatus(active):
I/flutter ( 5624): setState() or markNeedsBuild() called during build.
I/flutter ( 5624): This Overlay widget cannot be marked as needing to build because the framework is already in the
I/flutter ( 5624): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter ( 5624): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter ( 5624): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter ( 5624): Otherwise, the framework might not visit this widget during this build phase.

Voici un exemple de code

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
      routes: <String, WidgetBuilder> {
        "login" : (BuildContext context) => new LoginPage(),
      }
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  int _counter = 0;

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

      if(!isLoggedIn) {
        print("not logged in, going to login page");
        Navigator.of(context).pushNamed("login");
      }

    }


  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  void test() {
    print("hello");
  }

  @override
  Widget build(BuildContext context) {

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Text(
          'Button tapped $_counter time${ _counter == 1 ? '' : 's' }.',
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: new Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

}

class LoginPage extends StatefulWidget {
  LoginPage({Key key, this.title}) : super(key: key);

  final String title;

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

class _LoginPageState extends State<LoginPage> {
  @override
  Widget build(BuildContext context) {
    print("building login page");
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sign up / Log In"),
      ),
      ),
    );
  }
}

Je suppose que je fais quelque chose de mal, peut-être que l'abandon d'une construction de widget est à l'origine de cela. Cependant, comment puis-je y parvenir.

Fondamentalement: "Je vais sur ma page, si je ne suis pas connecté, allez sur la page de connexion"

Merci, Alexi

18
Alexi Coard

Essayez d'encapsuler votre appel Navigator:

Navigator.of(context).pushNamed("login");

dans un rappel planifié avec addPostFrameCallback :

SchedulerBinding.instance.addPostFrameCallback((_) {
  Navigator.of(context).pushNamed("login");
});

Vous aurez besoin de cette importation en haut de votre fichier:

import 'package:flutter/scheduler.Dart';

Comme alternative, considérez si vous pouvez simplement avoir la méthode build() de MyHomePage renvoyer un LoginPage au lieu d'un Scaffold si l'utilisateur n'est pas connecté. Cela interagira probablement mieux avec le bouton de retour, car vous ne voulez pas que l'utilisateur se retire de la boîte de dialogue de connexion avant d'avoir terminé la connexion.

30
Collin Jackson

Une autre approche consiste à effectuer la vérification de connexion avant une nouvelle page, qui nécessite une authentification, est ouverte. La page principale est réservée en tant que page "bienvenue"/info et lorsque l'utilisateur tape sur un élément du menu, la vérification de connexion est effectuée.

Connecté: une nouvelle page est ouverte. Déconnecté: la page de connexion est ouverte.

Travaille pour moi :)

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

  // it will navigate to login page as soon as this state is built
  Timer.run(() {
    Navigator.of(context).pushNamed("login");
  });
}
0
CopsOnRoad