Atamyrat Babayev
Atamyrat Babayev

Reputation: 890

Save state of each page inside of PageView with Bottom Navigation bar flutter

I have two main widgets inside of stack, which placed inside of main route(screen):

Each page of pageView is wrapped inside of CustomNavigator widget, and list of keys for navigators are placed inside of main route(screen). Navigation by using bottom navigation bar works fine, but when pushing to another rote inside of page and going to another page and back, the state of page with pushed route become to default state, what can I do with it? Here is my main screen's state:

const String MainRoute = '/';
const String AccountRoute = '/account';
const String CategoriesRoute = '/categories';
const String HomeRoute = '/home';
const String WishListRoute = '/wish_list';
const String ProductRoute = '/product';
class _MainState extends State<Main> {

  int _pressedPosition = 0;

  final List _screenStates = [
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>(),
    GlobalKey<NavigatorState>(), 
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          PageView(
            physics:new NeverScrollableScrollPhysics(),
            controller: _pageController,
            children: _mainScreens(),
          ),
          Align(
            alignment: Alignment.bottomCenter,
            child: CurvedNavigationBar(
              animationDuration: Duration(milliseconds: 200),
              backgroundColor: Colors.transparent,
              onTap: (int position) {
                _bottomTapped(position);
              },
              height: 60.0,
              items: <Widget>[...],
            ),
          )
        ],
      ),
    );
  }

  PageController _pageController = PageController(
    initialPage: 0,
    keepPage: true,
  );

  void _bottomTapped(int index) {
    setState(() {
      _pressedPosition = index;
      _pageController.animateToPage(index,
          duration: Duration(milliseconds: 300), curve: Curves.ease);
    });
  }
  
 List<Widget> _mainScreens() {
  return <Widget>[
    CustomNavigator(initialRoute: HomeView(), navigatorKey: _screenStates[0],),
    CustomNavigator(initialRoute: CategoriesView(), navigatorKey: _screenStates[1],),
    CustomNavigator(initialRoute: ShoppingCartView(), navigatorKey: _screenStates[2],),
    CustomNavigator(initialRoute: WishListView(), navigatorKey: _screenStates[3],),
    CustomNavigator(initialRoute: AccountView(), navigatorKey: _screenStates[4],),
  ];
}

Here is Custom navigator class:

class CustomNavigator extends StatelessWidget {
  final Widget initialRoute;
  final GlobalKey<NavigatorState> navigatorKey;

  CustomNavigator({@required this.initialRoute, @required this.navigatorKey});

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: navigatorKey,
      onGenerateRoute: _routes(initialRoute),
    );
  }

  //routing
  RouteFactory _routes(Widget initialRoute) {
    return (settings) {
      final Map<String, dynamic> arguments = settings.arguments;
      Widget screen;
      switch (settings.name) {
        case MainRoute:
          screen = initialRoute;
          break;

        case ProductRoute:
          screen = ProductView();
          break;

        default:
          return null;
      }
      return MaterialPageRoute(builder: (BuildContext context) => screen);
    };
  }
}

I already read https://medium.com/flutter/getting-to-the-bottom-of-navigation-in-flutter-b3e440b9386, https://medium.com/@Mr_Pepe/nested-navigation-with-a-bottom-navigation-bar-using-flutter-d3c5086fbcdc and http://bizz84.github.io/2018/07/07/Multiple-Navigators-BottomNavigationBar.html but anyway these topics are too difficult to understand.

In addition found this solution, but it doesn't work: https://github.com/indatawetrust/nested-navigation-demo-flutter

HELP! Thanks))

Upvotes: 0

Views: 3294

Answers (1)

Subhendu Pratap Singh
Subhendu Pratap Singh

Reputation: 623

PageView unloads tabs that aren't visible to save memory, that's why your state is getting lost. But you can force them to stay around by using the KeepAlive machinery. See AutomaticKeepAliveClientMixin for the simplest way to do that. That should work with the PageView used with tabs.You can use IndexedStack instead of PageView because it doesn't unload the widgets, it just displays the current active widget on top of others. Each Widget in IndexedStack returns its own Navigator like you are doing currently.So you can do something like this

IndexedStack(
      index: _pressedPosition,
      children: _mainScreens(), //return Views Here
    ),
  )

and then on click

setState(() {
      _pressedPosition = index;
    });

You can use BottomNavigationBar which is a part of Scaffold widget and made for just this purpose. Check this link for reference (the navigation part).

Upvotes: 2

Related Questions