如何在抽屉内添加一个抽屉?

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

strong text 当我按下抽屉中的设置然后打开一个新抽屉时。当我点击抽屉中的按钮时如何实现抽屉

image1 image2
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),
      )
    ]);
  }
}

使用 PageView.builder(),其中索引 0 是 firstPage(您的第一张带有常用抽屉的图像),索引 1 将是 selected 小部件(设置或探索)。我在 PageView 的索引 1 中的多个选项之间使用内部索引 myIndex select,那是因为如果我使用常规的 PageView 并给它一个所有选项的列表 [Drawer, Explorer, Settings] 如果你使用 controller.animateToPage() 你可以看到所有页面的过渡,例如,如果你在第 0 页并动画到第 2 页,你可以暂时看到第 1 页(就像你滚动一样水平)。

如果您不想看动画而直接跳转到该页面,您可以使用 controller.jumpToPage(index) 并且您不需要整个逻辑,它可能更容易

 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),
              );
           }
          },
        )
      );
  }
}

在这里,您只需告诉 PageView childCount 为 3(抽屉菜单、资源管理器和设置),然后执行一个 switch case 以在这 3 个索引之间跳转。您可以尝试在此示例中使用 animationToPage() 并查看我认为您的项目不希望出现的效果

这可能会晚一些,但另一个解决方案是在 Drawer 中构建 ScaffoldAppBar,并利用 build-in 导航行为。

请注意以下示例使用 Builder 以编程方式打开 Drawer,您也可以使用 GlobalKey.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MultiDrawers(),
    );
  }
}

class MultiDrawers extends StatelessWidget {
  const MultiDrawers({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(backgroundColor: Colors.teal),
      drawer: const FirstDrawer(),
      body: const Center(child: Text('multi-layer drawer example')),
    );
  }
}

class FirstDrawer extends StatelessWidget {
  const FirstDrawer({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: Scaffold(
        appBar: AppBar(
          title: const Text('1st drawer'),
          automaticallyImplyLeading: false, // hide hamburger icon
        ),
        drawer: const SecondDrawer(),
        body: Center(
          child: Builder(builder: (context) {
            return ElevatedButton(
              onPressed: () {
                Scaffold.of(context).openDrawer();
              },
              child: const Text('open 2nd drawer'),
            );
          }),
        ),
      ),
    );
  }
}

class SecondDrawer extends StatelessWidget {
  const SecondDrawer({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('2nd drawer'),
        backgroundColor: Colors.pink,
      ),
      body: const Center(
        child: Text('this is 2nd drawer'),
      ),
    );
  }
}