The app I am developing attempts to adopt, as much as possible, the most native experience for Android & iOS users.
To do so, the app runs a CupertinoApp
and a MaterialApp
.
On iOS, I use the CupertinoScaffold
showing a CupertinoTabBar
with BottomNavigationBarItems
. It performs very well as expected:
- pages are created only once, the first time I click on a tab;
- pages are restored when returning to a previously displayed tab: in one of my tab, there is a list and its scroll position is always maintained, persisted.
on Android, the story is different: I am using the Drawer
widget.
When I click on an entry, I call Navigator#push
to show the associated page. However, this will keep adding new instances of each entry's page in the stack.
I don't seem to be able to return to an existing page. At least, not how I can do it with iOS.
Looking at the Navigator
I see functions that seem to achieve what I am looking for:
popUntil
=> will show my existing screen, but at the expanses of all the other ones that will therefore make a sacrifice for the sake of just one page. So much ado for nothing...pushReplacement
=> will show a new instance of the target page and destroy the current one. Not desirable.
What am I missing ? How can I achieve that the CupertinoTabBar
seems to be able to do?
Well, I solved my issue by taking another direction.
Simply put I don't think there is a way, with the
Navigator
to achieve what I want.The solution I find out was: Keep state of widgets with Bottom Navigation Bar in Flutter
This guide suggests to use a
IndexedStack
that displays only one child at the time while keeping its state.So this is how I managed to make it work:
MaterialApp
home
to be a custom stateful widget calledMaterialHomePage
MaterialHomePage
builds aScaffold
:AppBar
and its title (the title of the active page);drawer
and its arguments (more on that later)body
is that so-called wonderfulIndexedStack
:children
to be the list of pages / widgets, the same pages available in the drawerindex
to be the property_selectedPageIndex
of yourMaterialHomePage
setState
occurs inside of which you may update the_selectedPageIndex
property as well as_selectedPageIndex
property`.Drawer
:Function
with the target page title & indexListTile
) as pages you have declared in theIndexedStack
displayed inMaterialHomePage
.At the end, what happens:
MaterialHomePage
gets notified (via callback) of the user choice which triggers asetStage
that will both:IndexedStack
withindex = 3
AppBar
's titleand voilà there you go: each page gets retained, no loss of state and a smooth navigation.
NB: if the user uses the Android's back button feature, at this point it will close the app since the
Navigator
stack is empty. Maybe there is a way to listen for such an event if you desire to default to the first entry / page (displayed at launch) if the user was in a another page.NB2: I also wonder if there is a way to animate page transitions.
PS: Let me know if the answers is a fine solution in which case I'll validate it. Or if you find a proper way to achieve it.