The template you are trying to build, even if it’s reasonable, seems like it cannot be presented out of the box with Flutter.
EDIT . The behavior you want to achieve requires the use of onGenerateRoute, but not yet written (Jan'18) ( doc ). See @Darky's answer for an example. It offers implementations of NestedRouteBuilder and NestedRoute , filling the gap.
Using a simple navigator from MaterialApp, navigating routes and pages (according to the doc ) are two main characteristics that deny what you want to achieve (at least directly). On the one hand, Navigator behaves like a stack, thereby pushing and popping out routes one on top of the next, etc., On other routes, either full-screen or modal - this means that they partially occupy the screen, but they prohibit interaction with widgets below . More explicitly, your paradigm seems to require simultaneous interaction with pages at different levels on the stack - this cannot be done this way.
In addition, it seems that the path paradigm is not only a hierarchy - a common frame → a specific subpage, but in the first case, the representation of the stack in the navigator . I deceived myself, but it becomes clear that we are reading this :
String initialRoute
final
The name of the first route displayed.
By default, this drops the dart: ui.Window.defaultRouteName.
If this line contains any / characters, then the line is divided into those characters and substrings from the beginning of the line to each of them, in turn, is used as routes for pressing.
For example, if the route / stock / HOOLI was used as the initial Route, then Navigator will start the following routes at startup: /, / stock, stock / HOLI. This provides deep linking, allowing the app to maintain predictable route history.
A possible workaround, as it follows, is to use the path to instantiate the child widgets, keeping the state variable in order to know what to show:
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', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new ActionPage(title: 'Flutter Demo Home Page'), routes: <String, WidgetBuilder>{ '/action/plus': (BuildContext context) => new ActionPage(sub: 'plus'), '/action/minus': (BuildContext context) => new ActionPage(sub: 'minus'), }, ); } } class ActionPage extends StatefulWidget { ActionPage({Key key, this.title, this.sub = 'plus'}) : super(key: key); final String title, sub; int counter; final Map<String, dynamic> subroutes = { 'plus': (BuildContext context, int count, dynamic setCount) => new PlusSubPage(count, setCount), 'minus': (BuildContext context, int count, dynamic setCount) => new MinusSubPage(count, setCount), }; @override ActionPageState createState() => new ActionPageState(); } class ActionPageState extends State<ActionPage> { int _main_counter = 0; String subPageState; @override void initState() { super.initState(); subPageState = widget.sub; } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('Testing subpages'), actions: <Widget>[ new FlatButton( child: new Text('+1'), onPressed: () { if (subPageState != 'plus') { setState(() => subPageState = 'plus'); setState(() => null); } }), new FlatButton( child: new Text('-1'), onPressed: () { if (subPageState != 'minus') { setState(() => subPageState = 'minus'); setState(() => null); } }), ], ), body: widget.subroutes[subPageState](context, _main_counter, (count) { _main_counter = count; })); } } class PlusSubPage extends StatefulWidget { PlusSubPage(this.counter, this.setCount); final setCount; final int counter; @override _PlusSubPageState createState() => new _PlusSubPageState(); } class _PlusSubPageState extends State<PlusSubPage> { int _counter = 0; @override void initState() { super.initState(); _counter = widget.counter; } void _incrementCounter() { setState(() { _counter++; widget.setCount(_counter); }); } @override Widget build(BuildContext context) { return new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new IconButton( icon: const Icon(Icons.add), onPressed: _incrementCounter, ), new Text( 'You have pushed the button this many times:', ), new Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ); } } class MinusSubPage extends StatefulWidget { MinusSubPage(this.counter, this.setCount); final setCount; final int counter; @override _MinusSubPageState createState() => new _MinusSubPageState(); } class _MinusSubPageState extends State<MinusSubPage> { int _counter = 0; @override void initState() { super.initState(); _counter = widget.counter; } void _decrementCounter() { setState(() { _counter--; widget.setCount(_counter); }); } @override Widget build(BuildContext context) { return new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new IconButton( icon: const Icon(Icons.remove), onPressed: _decrementCounter, ), new Text( 'You have pushed the button this many times:', ), new Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ); } }
This, however, does not have stack memory at a lower level. If you want to process the sequence of the widget routines, you can wrap the container routines in WillPopScope , indicating there what it should do when the user presses the back button and saves the sequence of routines on the stack. However, I do not want to offer such a thing.
My last suggestion is to implement simple routes - without "levels" - to manage custom transitions to hide changes to the "external" layout and transfer data through pages or save in the appropriate class, giving you the state of the application.
PS: also check out Hero animations, they can provide you with the continuity you are looking for between performances.