如何在 Flutter 中的 Scaffold.drawer 中保存 widget 的状态?

bin*_*iyu 5 flutter flutter-layout

我想将小部件的状态保留在Scaffold.drawer. The Scaffold.drawer是一个自定义小部件,其中有一个RaiseButton 。当单击按钮时,按钮中的文本发生变化。但是,当抽屉关闭并重新打开抽屉时,更改的文本将被重置。

AutomaticKeepAliveClientMixin<>我在自定义抽屉中使用了“with ” ,但它不起作用。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Flutter Demo"),
      ),
      drawer: Drawer(child: CustomDrawer(),),
      body: Center(
        child: Text("Flutter Demo"),
      ),
    );
  }
}

class CustomDrawer extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _CustomDrawerState();
  }
}

class _CustomDrawerState extends State<CustomDrawer> with AutomaticKeepAliveClientMixin<CustomDrawer> {

  String btnText = "Click!";

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Center(
      child: RaisedButton(onPressed: () {
        setState(() {
          btnText = "Clicked!!";
        });
      }, child: Text(btnText),),
    );
  }

}
Run Code Online (Sandbox Code Playgroud)

我希望即使抽屉关闭,小部件的状态也可以保持。

Aar*_*ers 5

为抽屉创建一个单独的小部件,然后在您需要的任何地方使用。

使用提供者管理抽屉状态

class DrawerStateInfo with ChangeNotifier {
  int _currentDrawer = 0;
  int get getCurrentDrawer => _currentDrawer;

  void setCurrentDrawer(int drawer) {
    _currentDrawer = drawer;
    notifyListeners();
  }

  void increment() {
    notifyListeners();
  }
}
Run Code Online (Sandbox Code Playgroud)

将状态管理添加到 Widget 树

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.teal,
        ),
        home: MyHomePage(title: 'Flutter Demo Home Page'),
      ),
      providers: <SingleChildCloneableWidget>[
        ChangeNotifierProvider<DrawerStateInfo>(
            builder: (_) => DrawerStateInfo()),
      ],
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

创建抽屉小部件以在应用程序中重用

class MyDrawer extends StatelessWidget {
  MyDrawer(this.currentPage);

  final String currentPage;

  @override
  Widget build(BuildContext context) {
    var currentDrawer = Provider.of<DrawerStateInfo>(context).getCurrentDrawer;
    return Drawer(
      child: ListView(
        children: <Widget>[
          ListTile(
            title: Text(
              "Home",
              style: currentDrawer == 0
                  ? TextStyle(fontWeight: FontWeight.bold)
                  : TextStyle(fontWeight: FontWeight.normal),
            ),
            trailing: Icon(Icons.arrow_forward),
            onTap: () {
              Navigator.of(context).pop();
              if (this.currentPage == "Home") return;

              Provider.of<DrawerStateInfo>(context).setCurrentDrawer(0);

              Navigator.of(context).pushReplacement(MaterialPageRoute(
                  builder: (BuildContext context) =>
                      MyHomePage(title: "Home")));
            },
          ),
          ListTile(
            title: Text(
              "About",
              style: currentDrawer == 1
                  ? TextStyle(fontWeight: FontWeight.bold)
                  : TextStyle(fontWeight: FontWeight.normal),
            ),
            trailing: Icon(Icons.arrow_forward),
            onTap: () {
              Navigator.of(context).pop();
              if (this.currentPage == "About") return;

              Provider.of<DrawerStateInfo>(context).setCurrentDrawer(1);

              Navigator.of(context).pushReplacement(MaterialPageRoute(
                  builder: (BuildContext context) => MyAboutPage()));
            },
          ),
        ],
      ),
    );
  }
}

Run Code Online (Sandbox Code Playgroud)

在您的页面之一中使用抽屉

class MyAboutPage extends StatefulWidget {
  @override
  _MyAboutPageState createState() => _MyAboutPageState();
}

class _MyAboutPageState extends State<MyAboutPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('About Page'),
      ),
      drawer: MyDrawer("About"),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Mah*_*loo 1

对于您的情况,您有 2 个选择:

  1. 您应该将您的状态保存在顶级小部件中。就你的情况而言_MyHomePageState
  2. 使用状态管理器,例如Redux, Bloc, ScopedModel。我认为ScopedModel在这种情况下对你来说很好。

否则,你无法控制 的状态Drawer。因为它会重新创建您Drawer通过 中的操作按钮调用的每一刻Appbar