Search code examples
flutterflutter-layoutflutter-dependenciesflutter-animationflutter-web

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


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