delmin
delmin

Reputation: 2690

Navigating through MaterialPageRoute

I've got 4 screen. X,A,B,C. The navigation pattern should be as follow

enter image description here

Here is code

X Screen

class X extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: FlatButton(
        child: Text('Navigate to A'),
        onPressed: () {
          A.show(context);
        },
      ),
    );
  }
}

A screen

class A extends StatelessWidget {
  static Future<void> show(BuildContext context) async {
    await Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => A(), fullscreenDialog: false),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: FlatButton(
          child: Text('Navigate to B'),
          onPressed: () {
            B.show(context);
          },
        ),
      ),
    );
  }
}

B class

class B extends StatelessWidget {
  static Future<void> show(BuildContext context) async {
    await Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => B(), fullscreenDialog: false),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: FlatButton(
          child: Text('Navigate to C'),
          onPressed: () {
            C.show(context);
          },
        ),
      ),
    );
  }
}

C class

class C extends StatelessWidget {
  static Future<void> show(BuildContext context) async {
    await Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => C(), fullscreenDialog: false),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: FlatButton(
          child: Text('Navigate back to A'),
          onPressed: () {
            A.show(context); //<=== here is problem
          },
        ),
      ),
    );
  }
}

Problem I've got is when I navigate from screen C back to screen A and press back button on app bar then it get me back to screen C. I need to be able to navigate back from C to B, B to A, and A to X but once I navigate from C to A I need to navigate back to X or again to B on pressing the button

UPDATE

I guess I kinda managed that with try and fail technique and honestly I don't understand why does it work as I want. Please if you know why this works and have an explanation then please provide an answer. Here is what I did

I've added new static function in Screen A

  static Future<void> back(BuildContext context) async {
    await Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(
            builder: (context) => A(),
            fullscreenDialog: false),
        ModalRoute.withName('/'));
  }

and call it in my screen C in my button

A.back(context)

Upvotes: 3

Views: 9052

Answers (2)

Johny Saini
Johny Saini

Reputation: 909

  class C extends StatelessWidget {
  static Future<void> show(BuildContext context) async {
         await Navigator.of(context).push(
              MaterialPageRoute(builder: (context) => C(), fullscreenDialog: false),  
   );
   }

    @override
      Widget build(BuildContext context) {
     return Scaffold(
     appBar: AppBar(),
     body: Center(
     child: FlatButton(
      child: Text('Navigate back to A'),
      onPressed: () {
        int count = 0;
             Navigator.of(context).popUntil((_) => count++ >= 2);
      },
    ),
  ),
);
 }
}

Upvotes: 1

Sergey Salnikov
Sergey Salnikov

Reputation: 1781

Change your code

  1. give a name to A page route
  2. on C page do popUntil on button
class A extends StatelessWidget {
  static Future<void> show(BuildContext context) async {
    await Navigator.of(context).push(
      MaterialPageRoute(
          builder: (context) => A(),
          settings: RouteSettings(name: 'A'), // <-- change 1 give a name
          fullscreenDialog: false),
    );
  }
...
class C extends StatelessWidget {
...  
  onPressed: () {
    Navigator.popUntil(context, (route) => route.settings.name == 'A'); //<=== will pop until A change 2
...

see it works in dartpad

working gist used in dartpad

Whats going on in your Update A.back?

  1. It's pushing new route with page A (old will be destroyed)
  2. And removes all routes till first route for now it X
  3. But if before X is more routes will remove them too

Drawback - on iOS swipe back behavior invoking Navigator.pop and there is no straight way to call your A.back in this case

  static Future<void> back(BuildContext context) async {
    await Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(
            builder: (context) => A(),
            fullscreenDialog: false),
        ModalRoute.withName('/'));
  }

Upvotes: 1

Related Questions