Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Navigator.popUntil Flutter

Tags:

flutter

I m doing a Flutter app and I would like to go back from page 4 to page 1. I have an error really strange :

Bad state : Future already completed

I created a simple project to reproduce this bug :

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      onGenerateRoute: routes,
    );
  }
}

Route routes(RouteSettings settings) {
  if (settings.name == '/page1') {
    return MaterialPageRoute(
      builder: (context) {
        return Page1();
      },
    );
  } else if (settings.name == '/page2') {
    return MaterialPageRoute(
      builder: (context) {
        return Page2();
      },
    );
  } else if (settings.name == '/page3') {
    return MaterialPageRoute(
      builder: (context) {
        return Page3();
      },
    );
  } else if (settings.name == '/page4') {
    return MaterialPageRoute(
      builder: (context) {
        return Page4();
      },
    );
  } else {
    return MaterialPageRoute(
      builder: (context) {
        return Page1();
      },
    );
  }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Page 1'),
            RaisedButton(
              child: Text('Go Page 2'),
              onPressed: () {
                Navigator.of(context).pushNamed('/page2');
              },
            )
          ],
        ),
      ),
    );
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Page 2'),
            RaisedButton(
              child: Text('Go Page 3'),
              onPressed: () {
                Navigator.of(context).pushNamed('/page3');
              },
            )
          ],
        ),
      ),
    );
  }
}

class Page3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Page 3'),
            RaisedButton(
              child: Text('Go Page 4'),
              onPressed: () {
                Navigator.of(context).pushNamed('/page4');
              },
            )
          ],
        ),
      ),
    );
  }
}

class Page4 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Page 4'),
            RaisedButton(
              child: Text('Go Back Page 1'),
              onPressed: () {
                Navigator.of(context).popUntil(ModalRoute.withName('/page1'));
              },
            )
          ],
        ),
      ),
    );
  }
}

How can I solve that ?

like image 241
fandro Avatar asked Feb 04 '19 22:02

fandro


2 Answers

Instead of:

          Navigator.of(context).push(
            MaterialPageRoute(
              builder: (context) => Page1(),
            ),
          );

use:

          Navigator.of(context).push(
            MaterialPageRoute(
              settings: RouteSettings(name: "/Page1"),
              builder: (context) => Page1(),
            ),
          );

and then you can use :

Navigator.of(context)
              .popUntil(ModalRoute.withName("/Page1"));
like image 172
geeekfa Avatar answered Sep 24 '22 12:09

geeekfa


For page_transition plugin

In case you are using named Routes and this Package for transitions between pages (and arguments):

MaterialApp(
 onGenerateRoute: (settings) => {
   switch (settings.name) {
      case "/yourRoute":
        final value = settings.arguments as String?; // only if you pass arguments
        return PageTransition(
          settings: RouteSettings(
            name: "/yourRoute", //HERE is where you name your route for using popUntil
          ),
          child: YourPage(
            parameters: value ?? "null",
          ),
          type: PageTransitionType.fade,
        );

     case "/yourNextRoute":
          ...

     }
   }
),

Edit your main like this to enable calling and using pop with named routes. This would look like this: Navigator.popUntil(context, ModalRoute.withName("/yourRoute")) or Navigator.pushNamed(context, "/yourRoute",arguments: "12345")

like image 35
Paul Avatar answered Sep 26 '22 12:09

Paul