如何通过 Stateless Widget Children 传递 GlobalKey

How to pass a GlobalKey through Stateless Widget Children

我正在尝试在我的应用程序中创建自定义菜单栏。现在,我遇到的最大问题是在发生 setState 后传递一个状态,当它扩展到它的子级时。

我考虑过继承,但根据我的尝试,所有继承都需要内联。我无法创建一个将子 [] 临时输入构造函数的小部件。

我目前的做法是使用 GlobalKey 来更新插入到 StateFul 中的子部件的状态,同时直接更新它们。

我的 MenuBar 的子项声明为:

  List<MenuBarItem> menuItems;

MenuBarItem 是一个抽象接口 class,我打算用它来限制可以作为 menuItems 输入到我的 MenuBar 的小部件。

abstract class iMenuItem extends Widget{}
class MenuBarItem extends StatefulWidget implements iMenuItem{

在这个脚本的一些迭代中,我有一个 bool isExpanded 作为 iMenuItem 的一部分,但确定它没有必要。

这是我当前迭代的代码:

我的主要:


void main() {
//  runApp(MainApp());
  //runApp(InherApp());
  runApp(MenuBarApp());
}


class MenuBarApp extends StatelessWidget{

  @override
  Widget build(BuildContext context){

    return MaterialApp(
      home: Scaffold(
        body: MenuBar(
          menuItems: [
            // This one does NOT work and is where I'm trying to get the 
            // value to update after a setState
            MenuBarItem(
              myText: 'Outsider',
            ),
          ],
        ),

      ),

    );
  }
}


我的代码:


import 'package:flutter/material.dart';



/// Primary widget to be used in the main()
class MenuBar extends StatefulWidget{

  List<MenuBarItem> menuItems;

  MenuBar({
    required this.menuItems,
  });

  @override
  State<MenuBar> createState() => MenuBarState();

}

class MenuBarState extends State<MenuBar>{

  bool isExpanded = false;
  late GlobalKey<MenuBarContainerState> menuBarContainerStateKey;
  @override
  void initState() {
    super.initState();
    menuBarContainerStateKey = GlobalKey();
  }

  @override
  Widget build(BuildContext context){
      return MenuBarContainer(
          menuItems: widget.menuItems,
      );

  }

}


class MenuBarContainer extends StatefulWidget{

  List<MenuBarItem> menuItems;
  late Key key;
  MenuBarContainer({
    required this.menuItems,
        key,
  }):super(key: key);

  @override
  MenuBarContainerState createState() => MenuBarContainerState();

}

class MenuBarContainerState extends State<MenuBarContainer>{

  bool isExpanded =  false;

  @override
  void initState() {
    super.initState();
    isExpanded = false;
  }

  @override
  Widget build(BuildContext context){


    List<Widget> myChildren = [
      ElevatedButton(
        onPressed: (){
          setState((){
            this.isExpanded = !this.isExpanded;
          });
        },
        child: Text('Push Me'),
      ),
      // This one works. No surprise since it's in-line
      MenuBarItem(isExpanded: this.isExpanded, myText: 'Built In'),
    ];

    myChildren.addAll(widget.menuItems);

    return Container(
      child: Column(
        children: myChildren,
      ),
    );
  }
}

/// The item that will appear as a child of MenuBar
/// Uses the iMenuItem to limit the children to those sharing
/// the iMenuItem abstract/interface
class MenuBarItem extends StatefulWidget implements iMenuItem{

  bool isExpanded;
  String myText;
  MenuBarItem({
    key,
    this.isExpanded = false,
    required this.myText,

  }):super(key: key);

  @override
  State<MenuBarItem> createState() => MenuBarItemState();

}

class MenuBarItemState extends State<MenuBarItem>{


  @override
  Widget build(BuildContext context){
    GlobalKey<MenuBarState> _menuBarState;

    return Row(
      children: <Widget> [
        Text('Current Status:\t${widget.isExpanded}'),
        Text('MenuBarState GlobalKey:\t${GlobalKey<MenuBarState>().currentState?.isExpanded ?? false}'),
        Text(widget.myText),
      ],
    );
  }
}

/// To give a shared class to any children that might be used by MenuBar
abstract class iMenuItem extends Widget{

}



我已经为此花了 3 天的时间,所以任何帮助将不胜感激。

谢谢!!

我建议使用 ChangeNotifierChangeNotifierProviderConsumercontext.read 来管理状态。您必须添加 this package 和此导入:import 'package:provider/provider.dart';。步骤:

  1. 设置一个 ChangeNotifier 持有 isExpanded 值,用一个 setter 通知听众:
class MyNotifier with ChangeNotifier {
  bool _isExpanded = false;
  bool get isExpanded => _isExpanded;
  set isExpanded(bool isExpanded) {
    _isExpanded = isExpanded;
    notifyListeners();
  }
}
  1. 将以上内容作为 ChangeNotifierProvider 插入您的小部件树中 MenuBar:
class MenuBarState extends State<MenuBar> {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
        create: (context) => MyNotifier(),
        child: MenuBarContainer(
          menuItems: widget.menuItems,
        ));
  }
}

在此之后,您可以轻松地从 ChangeNotifierProvider 下的小部件树中的任何位置读取和写入 isExpanded 值,例如:

ElevatedButton(
  onPressed: () {
    setState(() {
      final myNotifier = context.read<MyNotifier>();
      myNotifier.isExpanded = !myNotifier.isExpanded;
    });
  },
  child: Text('Push Me'),
),

如果您想在 isExpanded 更改时使用此状态自动构建某些内容,请使用 Consumer,它会在每次更改时自动通知,例如:

class MenuBarItemState extends State<MenuBarItem> {
  @override
  Widget build(BuildContext context) {
    return Consumer<MyNotifier>(builder: (context, myNotifier, child) {
      return Row(
        children: <Widget>[
          Text('Current Status:\t${myNotifier.isExpanded}'),
          Text(widget.myText),
        ],
      );
    });
  }
}