如何在为不同屏幕使用单一应用栏的 Flutter 导航抽屉中创建可扩展列表

How to create an expandable list in Flutter navigation drawer that uses single app bar for different screens

我需要在 flutter 中开发一个导航抽屉,我是 flutter 的新手,我正在使用以下代码,这是按预期创建菜单,但问题是

1.handling screen navigation 
2.maintaining state and navigating back to the screen which is previously opened

我无法在有状态小部件中使用此代码,因为我需要维护导航抽屉的状态

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:skubiq/second_screen.dart';
import 'package:skubiq/third_screen.dart';

class ExpansionList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
          itemCount: data.length,
          itemBuilder: (BuildContext context, int index) => EntryItem(
            data[index],
          ),
        );
  }
}

// Welcome to another flutter tutorial
// In this video we will see how to create a multi-level Expansion List
// First Let's create a class for each row in the Expansion List

class Entry {
  final String title;
  final List<Entry>
  children; // Since this is an expansion list ...children can be another list of entries
  Entry(this.title, [this.children = const <Entry>[]]);
}

// This is the entire multi-level list displayed by this app
final List<Entry> data = <Entry>[
  Entry(
    'Chapter A',
    <Entry>[
      Entry('Section A0',
        // <Entry>[
        //   Entry('Item A0.1'),
        //   Entry('Item A0.2'),
        //   Entry('Item A0.3'),
        // ],
      ),
      Entry('Section A1'),
      Entry('Section A2'),
    ],
  ),
  // Second Row
  Entry('Chapter B', <Entry>[
    Entry('Section B0'),
    Entry('Section B1'),
  ]),
  Entry(
    'Chapter C',
    <Entry>[
      Entry('Section C0'),
      Entry('Section C1'),
      Entry(
        'Section C2',
        <Entry>[
          Entry('Item C2.0'),
          Entry('Item C2.1'),
          Entry('Item C2.2'),
          Entry('Item C2.3'),
        ],
      )
    ],
  ),
];

// Create the Widget for the row
class EntryItem extends StatelessWidget {
  const EntryItem(this.entry);

  final Entry entry;

  // This function recursively creates the multi-level list rows.
  Widget _buildTiles(Entry root) {
    if (root.children.isEmpty) {
      return ListTile(
        title: Text(root.title),
        onTap: (){
          Fluttertoast.showToast(msg: root.title);
          _getDrawerItemWidget(root.title);
        },
      );
    }
    return ExpansionTile(
      key: PageStorageKey<Entry>(root),
      title: Text(root.title),
      children: root.children.map<Widget>(_buildTiles).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: _buildTiles(entry));
  }

  _getDrawerItemWidget(String screenName) {
    switch (screenName) {
      case "Section A0":
        return new ThirdScreen();
      case "Section A1":
        return new SecondScreen();
      case "Section A2":
        return new ThirdScreen();

      default:
        return new Text("Error");
    }
  }
}

基本上我是一名 android 应用程序开发人员,我期待实现以下概念,例如带有导航抽屉的 sigle activity 并在 flutter 中处理多个片段

请帮助我达到要求

任何源代码建议或完全实现的代码都对我的需要有帮助

最后,这里没有人回答,我四处寻找解决问题的方法

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:skubiq/Constants/app_constants_ui.dart';
import 'package:skubiq/ModelClasses/nav_drawer_menu_entries.dart';
import 'package:skubiq/Widgets/custom_appbar.dart';
import 'package:skubiq/screens/home_screen.dart';
import 'package:skubiq/screens/second_screen.dart';
import 'package:skubiq/screens/first_screen.dart';
import 'package:skubiq/screens/third_screen.dart';

import '../Constants/string_const.dart';

class NavDrawer extends StatefulWidget with PreferredSizeWidget {
  @override
  State<StatefulWidget> createState() {
    return new NavDrawerState();
  }

  @override
  // TODO: implement preferredSize
  Size get preferredSize => throw UnimplementedError();
}

class NavDrawerState extends State<NavDrawer> {
  int _selectedDrawerIndex = 0;
  String screenName = "Home";

  final ScrollController scroll = ScrollController();

  @override
  void dispose() {
    scroll.dispose();
    super.dispose();
  }



  _getDrawerItemWidget(String pos) {
    switch (pos) {
      case "Home":
        return new HomeScreen();
      case "Receiving":
        return new FirstScreen();
      case "Putaway":
        return new SecondScreen();
      case "Pallet Transfer":
        return new ThirdScreen();

      default:
        return new Text("Error");
    }
  }

  _onSelectItem(String screen) {
    setState(() => screenName = screen);
    Navigator.of(context).pop(); // close the drawer
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(
        // here we display the title corresponding to the fragment
        // you can instead choose to have a static title
        child: Text(screenName),
        context: context,
      ),
      drawer: Drawer(
          child: Container(
        decoration: AppConstants.customBoxDecoration, 
        //you can use your own boxdecoration
        child: Column(
          children: <Widget>[
             UserAccountsDrawerHeader(
                decoration: AppConstants.customBoxDecoration,
                currentAccountPicture: new CircleAvatar(
                  radius: 60.0,
                 // backgroundColor: const Color(0xFF778899),
                  backgroundImage: AssetImage('assets/logo.png'), 
                ),
                accountName: new Text("Name"),
                accountEmail: new Text("mail")),
            Flexible(
              child: ListView.builder(
                  shrinkWrap: true,
                  controller: scroll,
                  itemCount: StringConstants.menuList.length,
                  itemBuilder: (BuildContext context, int index) => buildList(
                    StringConstants.menuList[index],
                      ))
            )
          ],
        ),
      )),
      body: _getDrawerItemWidget(screenName),
    );
  }

  // This function recursively creates the multi-level list rows.
  Widget _buildTiles(Entry root) {
    if (root.children.isEmpty) {
      return ListTile(
        leading: Icon(root.icon),
        title: Text(
          root.title,
          style: AppConstants.textStyleNavDrawer,
        ),
        onTap: () {
          Fluttertoast.showToast(msg: root.title);
          _onSelectItem(root.title);
        },
      );
    }
    return ExpansionTile(
      key: PageStorageKey<Entry>(root),
      maintainState: true,
      title: Text(
        root.title,
        style: AppConstants.textStyleNavDrawer,
      ),
      children: root.children.map<Widget>(_buildTiles).toList(),
    );
  }

  Widget buildList(Entry entry) {
    return _buildTiles(entry);
  }
}

自定义应用栏class


import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:skubiq/Constants/app_constants_ui.dart';
import 'package:skubiq/Constants/custom_colors.dart';

class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
  final Widget child;
  final double height;
  final BuildContext context;

  CustomAppBar(
      {required this.child,
      this.height = kToolbarHeight,
      required this.context});

  @override
  Size get preferredSize => Size.fromHeight(height);

  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: child,
      flexibleSpace: Container(
        decoration: AppConstants.customBoxDecoration,
      ),
      actions: <Widget>[
        IconButton(
          icon: Icon(
            Icons.qr_code_scanner,
            color: Colors.white,
          ),
          onPressed: () {

            Fluttertoast.showToast(msg: context.toString());
            // do something
          },
        )
      ],
    );
  }
}


应用常量class


import 'package:flutter/material.dart';
import 'package:skubiq/Constants/custom_colors.dart';

class AppConstants {

  static const BoxDecoration customBoxDecoration = BoxDecoration(
      gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [CustomColors.iconSplashColor, CustomColors.iconColor]));
// you define your own colors

  static const TextStyle textStyleNavDrawer = TextStyle(
    color: Colors.white);



}

如果您需要针对不同屏幕使用单个应用栏,请尝试此示例