Flutter navigation for part of screen
Asked Answered
B

4

18

How can I push a widget in the frame of another widget? For example I have a Column with 2 Containers where every Container takes half of the screen. I'd like to make a navigation e.g. only in the bottom container. The same logic as in iOS when the container view has it's own UINavigationController.

As I understood MaterialPageRoute can push widgets only to fullscreen and there aren't any other Route classes, except abstract ones. Maybe I should make my own subclass of ModalRoute/TransitionRoute?

Buttonhole answered 22/6, 2018 at 10:53 Comment(2)
Do you need some animation or why are you not just using a condition to replace the content of your Container?Paprika
@Paprika I'd like to use hero widget, which animation is triggered by Navigator.Buttonhole
A
28

You can use the Navigator widget to provide any number of individual navigators in your app. Each Navigator will maintain it's own navigation stack. For example, if you wanted to split your app vertically with each half having it's own navigation stack:

Column(
  children: <Widget>[
    Navigator(...),
    Navigator(...)
  ]
)

If you do this, you should consider how you want to handle the Android back button (now that you technically have 3 navigators in your app). By default, it will only listen to your root navigator so you will have to provide a WillPopScope widget somewhere in your widget hierarchy to capture back button events and pop from the appropriate navigator.

Academic answered 9/9, 2018 at 19:16 Comment(3)
How do you exactly control that two navigators? How do you tell one navigation to push while the other to pop? I could post a question if you prefer to answer it in another question. Thanks in advance.Spun
From the children widgets of the Navigator, Navigator.of(context) will return the correct parent Navigator.Academic
@KirollosMorkos Can you please provide a example.Pieter
I
12

One possible solution would be to create a new MaterialApp on that portion of the screen and handle everything from there like a regular app (just with different screen size) like so:

Column(
        children: <Widget>[
          Container(
            height: constraints.maxHeight * 0.5,
            width: constraints.maxWidth,
          ),
          Container(
              height: constraints.maxHeight * 0.5,
              width: constraints.maxWidth,
              child: MaterialApp(
                  debugShowCheckedModeBanner: false,
                  theme: ThemeData(
                    primaryColor: Color.fromRGBO(86, 86, 86, 1.00),
                  ),
                  initialRoute: '/W1',
                  routes: {
                    '/W1': (context) => WidgetOne(),
                    '/W2': (context) => WidgetTwo(),
                  })),
        ],
      ),

Then handle the routing from withing the widgets like so:

class WidgetOne extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () {
      Navigator.pushNamed(context, '/W2');
    },
    child: Container(color: Colors.green));
    }
  }
}

class WidgetTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () {
      Navigator.pushNamed(context, '/W1');
    },
    child: Container(color: Colors.pink));
    }
  }
}

Result: https://i.sstatic.net/qyJ5N.gif

Instead answered 3/3, 2020 at 15:32 Comment(1)
Thank you very much @Yodart. this is just what I was looking for 👌Ramsay
K
10

You can use Navigator as a child for the specific part you want to make that. And I used WillPopScope to go back to the previous screen if there is one. and make sure to use GlobalKey() to separate each navigator and give it a unique key. My code :

var keyOne = GlobalKey<NavigatorState>();
var keyTwo = GlobalKey<NavigatorState>();
return Column(
  children: [
    Expanded(
      child: Container(
        child: WillPopScope(
          onWillPop: () async => !await keyOne.currentState.maybePop(),
          child: Navigator(
            key: keyOne,
            onGenerateRoute: (routeSettings) {
              return MaterialPageRoute(
                builder: (context) => ScreenOne(),
              );
            },
          ),
        ),
      ),
    ),
    Expanded(
      child: Container(
        child: WillPopScope(
          onWillPop: () async => !await keyTwo.currentState.maybePop(),
          child: Navigator(
            key: keyTwo,
            onGenerateRoute: (routeSettings) {
              return MaterialPageRoute(
                builder: (context) => ScreenTwo(),
              );
            },
          ),
        ),
      ),
    ),
  ],
);
Kappa answered 27/5, 2021 at 10:47 Comment(0)
C
0

The concept you are looking for is Nested Navigation in flutter

Ciaphus answered 4/1 at 14:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.