如何通过 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 天的时间,所以任何帮助将不胜感激。
谢谢!!
我建议使用 ChangeNotifier
、ChangeNotifierProvider
、Consumer
和 context.read
来管理状态。您必须添加 this package 和此导入:import 'package:provider/provider.dart';
。步骤:
- 设置一个
ChangeNotifier
持有 isExpanded
值,用一个 setter 通知听众:
class MyNotifier with ChangeNotifier {
bool _isExpanded = false;
bool get isExpanded => _isExpanded;
set isExpanded(bool isExpanded) {
_isExpanded = isExpanded;
notifyListeners();
}
}
- 将以上内容作为
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),
],
);
});
}
}
我正在尝试在我的应用程序中创建自定义菜单栏。现在,我遇到的最大问题是在发生 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 天的时间,所以任何帮助将不胜感激。
谢谢!!
我建议使用 ChangeNotifier
、ChangeNotifierProvider
、Consumer
和 context.read
来管理状态。您必须添加 this package 和此导入:import 'package:provider/provider.dart';
。步骤:
- 设置一个
ChangeNotifier
持有isExpanded
值,用一个 setter 通知听众:
class MyNotifier with ChangeNotifier {
bool _isExpanded = false;
bool get isExpanded => _isExpanded;
set isExpanded(bool isExpanded) {
_isExpanded = isExpanded;
notifyListeners();
}
}
- 将以上内容作为
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),
],
);
});
}
}