how to add one more drawer inside a drawer in flutter?

Issue

strong text When I pressed on setting in drawer and then open a new drawer. How to implement a drawer when I click on button in a drawer.

image1 image2

Solution

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(),
        drawer: MyDrawer(),
        body: Center(
          child: Center(child: Text('Text')),
        ),
      ),
    );
  }
}

class MyDrawer extends StatefulWidget {
  @override
  _DrawerState createState() => _DrawerState();
}

class _DrawerState extends State<MyDrawer> {
  int myIndex;
  PageController _controller;

  @override
  void initState() {
    super.initState();
    _controller = PageController(initialPage: 0);
  }

  //The Logic where you change the pages
  _onChangePage(int index){
    if(index != 0) setState(() => myIndex = index); //change myIndex if you're Selecting between Settings and Explore
    _controller.animateToPage(index.clamp(0, 1),
      duration: const Duration(milliseconds: 500), curve: Curves.linear);
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Drawer(
        child: PageView.builder(
          controller: _controller,
          physics: NeverScrollableScrollPhysics(), //so the user can not move between pages
          itemCount: 2,
          itemBuilder: (context, index) {
            // Original Drawer
            if (index == 0) return MyWidget(
                explore: () => _onChangePage(1),
                settings: () => _onChangePage(2),
              );
            //Second Drawer form the PageView
              switch(myIndex){
                case 1:
                  return MyExploreAll(goBack: () => _onChangePage(0));
                case 2:
                default:
                  return MySettings(goBack: () => _onChangePage(0));
              }
          },
        )
      );
  }
}

//The Menu Drawer (Your first image)
class MyWidget extends StatelessWidget {
  final VoidCallback explore;
  final VoidCallback settings;

  MyWidget({this.explore, this.settings});

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverList(
          delegate: SliverChildListDelegate([
            ListTile(
              title: Text('Send Money'),
              onTap: () => print('Send Money'),
            ),
            ListTile(
              title: Text('Explore All Amazon Pay'),
              onTap: () => print('Explore All Amazon Pay'),
            ),
            const Divider(color: Colors.grey, thickness: 1,),
            ListTile(
              title: Text('Try Prime'),
              onTap: () => print('Try Prime'),
            ),
            ListTile(
              title: Text('Explore All Programs'),
              trailing: const Icon(Icons.arrow_forward_ios),
              onTap: explore,
            ),
            const Divider(color: Colors.grey, thickness: 1,),
            ListTile(
              title: Text('Fun Zone'),
              onTap: () => print('Fun Zone'),
            ),
            const Divider(color: Colors.grey, thickness: 1,),
            //More Stuff
            ListTile(
              title: Text('Settings'),
              trailing: const Icon(Icons.arrow_forward_ios),
              onTap: settings,
            ),
          ])
        )
      ],
    );
  }
}

// The settings Drawer(second image)
class MySettings extends StatelessWidget {
  final VoidCallback goBack;

  MySettings({this.goBack});

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverList(
          delegate: SliverChildListDelegate([
            ListTile(
              leading: const Icon(Icons.arrow_back_ios),
              title: Text('Main Menu'),
              onTap: goBack,
            ),
            ListTile(
              title: Text('Settings', textScaleFactor: 3,),
              onTap: () => print('Settings'),
            ),
            const Divider(color: Colors.grey, thickness: 1,),
            ListTile(
              title: Text('Change Country'),
              onTap: () => print('Change Country'),
            ),
            ListTile(
              title: Text('ETC'),
              onTap: () => print('ETC'),
            ),
            const Divider(color: Colors.grey, thickness: 1,),
            ListTile(
              title: Text('Dummy Text'),
              onTap: () => print('Dummy Text'),
            ),
          ])
        )
      ],
    );
  }
}

class MyExploreAll extends StatelessWidget {
  final VoidCallback goBack;

  MyExploreAll({this.goBack});

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverList(
          delegate: SliverChildListDelegate([
            ListTile(
              leading: const Icon(Icons.arrow_back_ios),
              title: Text('Main Menu'),
              onTap: goBack,
            ),
            ListTile(
              title: Text('Explore All', textScaleFactor: 3,),
              onTap: () => print('Explore'),
            ),
            const Divider(color: Colors.grey, thickness: 1,),
          ])
        )
      ],
    );
  }
}


class MyInnerDrawer extends StatelessWidget {
  final String name;
  final PageController _controller;

  MyInnerDrawer(this._controller, this.name);

  @override
  Widget build(BuildContext context) {
    return Column(children: [
      ListTile(
        title: Text(name),
        trailing: const Icon(Icons.arrow_back_ios),
        onTap: () => _controller.animateToPage(0,
            duration: const Duration(milliseconds: 500), curve: Curves.linear),
      )
    ]);
  }
}

Using a PageView.builder() where the index 0 is the firstPage (your first image with the usual drawer) and index 1 would be the selected widget (Settings or Explore). I use an inner index myIndex to select between the multiple options in the index 1 of the PageView, thats because if I use a regular PageView and give it a list of all the options [Drawer, Explorer, Settings] if you use the controller.animateToPage() you could see the transition of all the pages, for example if you’re in the page 0 and animate to page 2 you could see the page 1 for a moment (just like if you were scrolling horizontally).

If you don’t want to see the animation and just jump directly to that page you can use controller.jumpToPage(index) and you wouldn’t need that whole logic, it could be easier

 class _DrawerState extends State<MyDrawer> {
  PageController _controller;

  @override
  void initState() {
    super.initState();
    _controller = PageController(initialPage: 0);
  }

  _onChangePage(int index){
    _controller.jumpToPage(index);
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Drawer(
        child: PageView.builder(
          controller: _controller,
          physics: NeverScrollableScrollPhysics(),
          itemCount: 3,
          itemBuilder: (context, index) {
            switch(index){
             case 1:
              return MyExploreAll(goBack: () => _onChangePage(0));
             case 2:
              return MySettings(goBack: () => _onChangePage(0));
             case 0:
             default:
               return MyWidget(
                explore: () => _onChangePage(1),
                settings: () => _onChangePage(2),
              );
           }
          },
        )
      );
  }
}

Here you just tell the PageView the childCount is 3 (the Drawer menu, Explorer and Settings) and just do a switch case to jump between those 3 indexes. You could try use animationToPage() in this example and see the effect that I beleive would be undesirable for your project

Answered By – EdwynZN

Answer Checked By – Jay B. (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *