1

In the app, I am using PageView as home and 3 pages in it - Profile, Console, Settings with AutomaticKeepAliveClientMixin extension. In it, 2 of the pages(Profile and Console) have a 'Side Menu' screen using PageView again.

The problem is that when I switch between home pages, I want that if the 'Side Menu' is open on any page, it(second PageView) should jump to the initial page.

Here is the reduced version of the code-

Material app-

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home();
    );
  }
}

Home Widget -

class Home extends StatefulWidget {
  Home({Key key}) : super(key: key);
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  int _selectedIndex = 0;
  final pageController = PageController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
                body: PageView(
                  controller: pageController,
                  physics: PageScrollPhysics(
                      parent: ScrollPhysics(
                          parent: NeverScrollableScrollPhysics())),
                  children: <Widget>[
                    Tab1(),
                    Tab2(),
                    Tab3(),
                  ],
                ),
                //to set the bottom navigation bar and not reset the entire tree
                bottomNavigationBar: StatefulBuilder(
                  builder: (BuildContext context, setState) {
                    return BottomNavigationBar(
                      currentIndex: _selectedIndex,
                      selectedItemColor: Colors.green[800],
                      onTap: (index) {
                        setState(() {
                          _selectedIndex = index;
                        });
                        pageController.jumpToPage(index);
                      },
                      items: const <BottomNavigationBarItem>[
                        BottomNavigationBarItem(
                            icon: Icon(Icons.person), label: 'Profile'),
                        BottomNavigationBarItem(
                            icon: Icon(Icons.connect_without_contact), label: 'Console'),
                        BottomNavigationBarItem(
                            icon: Icon(Icons.settings), label: 'Settings')
                      ],
                    );
                  },
                ),
              );
  }
}

Same three pages -

class Tab1 extends StatefulWidget {
  @override
  _Tab1State createState() => _Tab1State();
}

class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {
  final controller = PageController();

  //to use back button to go back to initial screen when poped
  bool onWillPop() {
    pageController.previousPage(
      duration: Duration(milliseconds: 200),
      curve: Curves.linear,
    );
    return false;
  }

  @override
  get wantKeepAlive {
    return true;
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);

    return PageView(
      controller: controller,
      children: [
        Scaffold(
          appBar:
              AppBar(title: Text('Profile'), backgroundColor: Colors.grey[200]),
        ),
        //so that back button brings user back to initial screen
        WillPopScope(
          onWillPop: () => Future.sync(onWillPop),
          child: Scaffold(
            appBar: AppBar(
              title: Text('Side Menu Screen'),
            ),
          ),
        )
      ],
    );
  }
}

class Tab2 extends StatefulWidget {
  @override
  _Tab2State createState() => _Tab2State();
}

class _Tab2State extends State<Tab2> with AutomaticKeepAliveClientMixin<Tab2> {
  final controller = PageController();

  //to use back button to go back to initial screen when poped
  bool onWillPop() {
    pageController.previousPage(
      duration: Duration(milliseconds: 200),
      curve: Curves.linear,
    );
    return false;
  }

  @override
  get wantKeepAlive {
    return true;
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);

    return PageView(
      controller: controller,
      children: [
        Scaffold(
          appBar:
              AppBar(title: Text('Console'), backgroundColor: Colors.grey[200]),
        ),
        //so that back button brings user back to initial screen
        WillPopScope(
          onWillPop: () => Future.sync(onWillPop),
          child: Scaffold(
            appBar: AppBar(
              title: Text('Side Menu Screen'),
            ),
          ),
        )
      ],
    );
  }
}

class Tab3 extends StatefulWidget {
  @override
  _Tab3State createState() => _Tab3State();
}

class _Tab3State extends State<Tab3> with AutomaticKeepAliveClientMixin<Tab3> {
  final controller = PageController();

  //to use back button to go back to initial screen when poped
  bool onWillPop() {
    pageController.previousPage(
      duration: Duration(milliseconds: 200),
      curve: Curves.linear,
    );
    return false;
  }

  @override
  get wantKeepAlive {
    return true;
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);

    return PageView(
      controller: controller,
      children: [
        Scaffold(
          appBar:
              AppBar(title: Text('Settings'), backgroundColor: Colors.grey[200]),
        ),
        //so that back button brings user back to initial screen
        WillPopScope(
          onWillPop: () => Future.sync(onWillPop),
          child: Scaffold(
            appBar: AppBar(
              title: Text('Side Menu Screen'),
            ),
          ),
        )
      ],
    );
  }
}

Possible ways-

  • Detect when the tab or page goes off-screen and call the controller.jumpToPage() method. (best if possible)

Something like this-

 @override
    void dispose() {
      if (controller.hasClients) {
        controller.jumpToPage(controller.initialPage);
      }
      super.dispose();
    }
  • Listen to changes in the first PageView by onPageChanged property.
  • Pop willPopScope after checking if its pushed.

Thanks for all your help...

prakhar tomar
  • 933
  • 1
  • 8
  • 10

0 Answers0