如何在Flutter中从另一个StatefulWidget设置/更新StatefulWidget的状态?
如何在Flutter中从另一个StatefulWidget设置/更新StatefulWidget的状态?
例如,在下面的代码中,加号按钮可以更新文本,但是减号按钮不能。
但是,如果我们按下FloatingActionButton,状态会被刷新。
减号按钮改变了变量的值,但没有更新父部件的状态。
这是代码...
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
int number;
EdgeInsets globalMargin = const EdgeInsets.symmetric(horizontal: 20.0, vertical: 20.0);
TextStyle textStyle = const TextStyle(
fontSize: 100.0,
color: Colors.black,
);
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State
@override
void initState() {
super.initState();
number = number ?? 0;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Column(
children:
new Text(
number.toString(),
style: textStyle,
),
new GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
scrollDirection: Axis.vertical,
children:
new InkResponse(
child: new Container(
margin: globalMargin,
color: Colors.green,
child: new Center(
child: new Text(
"+",
style: textStyle,
),
)),
onTap: () {
setState(() {
number = number + 1;
});
},
),
new Sub(),
],
),
],
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
setState(() {});
},
child: new Icon(Icons.update),
),
);
}
}
class Sub extends StatefulWidget {
@override
_SubState createState() => new _SubState();
}
class _SubState extends State {
@override
Widget build(BuildContext context) {
return new InkResponse(
child: new Container(
margin: globalMargin,
color: Colors.red,
child: new Center(
child: new Text(
"-",
style: textStyle,
),
)),
onTap: () {
setState(() {
number = number - 1;
});
},
);
}
}
在Flutter中,有时候我们需要在一个StatefulWidget中的子部件中调用另一个StatefulWidget的方法,或者在父部件中调用子部件的方法。这篇文章将介绍如何实现这样的功能。
在给出的代码示例中,有一个父部件ParentPage和一个子部件ChildPage。父部件中有一个按钮,点击按钮时会调用子部件的方法;子部件中也有一个按钮,点击按钮时会调用父部件的方法。
为了实现在父部件中调用子部件的方法,我们可以使用GlobalKey来获取子部件的状态。在这个示例中,ParentPage中定义了一个名为_key的GlobalKey<ChildPageState>变量,然后将它传递给ChildPage的key属性。这样,在父部件中就可以通过_key.currentState来获取子部件的状态,进而调用子部件的方法。
为了在子部件中调用父部件的方法,我们可以在子部件中定义一个VoidCallback类型的属性function,该属性会在子部件中的按钮点击事件中调用。然后,将父部件中的方法作为参数传递给子部件的function属性。
当然,我们也可以通过使用GlobalKey在其他类中调用_ChildPageState。只需将_ChildPageState的私有标识符_去掉即可。
在处理多个子部件的情况下,我们可以为每个子部件创建一个对应的GlobalKey。但需要注意的是,使用GlobalKey可能会在设备上有一定的性能开销,因此需要谨慎使用。
总结起来,要实现在Flutter中从一个StatefulWidget中的子部件调用另一个StatefulWidget的方法,或者在父部件中调用子部件的方法,我们可以使用GlobalKey来获取子部件的状态,并通过该状态调用相应的方法。此外,我们还可以在子部件中定义一个属性,将父部件的方法传递给子部件,在子部件中调用该方法。需要注意的是,GlobalKey的使用可能会带来一定的性能开销,需要慎重考虑。
如何从Flutter中的其他StatefulWidget设置/更新State?
问题的原因是我们想要在一个StatefulWidget中更新另一个StatefulWidget的状态。以下是一些旧的/不推荐/失败的解决方案:
1. 解决方案1:创建一个_MyHomePageState
的全局实例,在_SubState
中使用此实例作为_myHomePageState.setState
。
2. 解决方案2:不需要创建全局实例,只需将父实例传递给子小部件。
3. 解决方案3:从父小部件传递回调到子小部件,以从子小部件更新父小部件的状态。
最佳解决方案是使用包stream_mixin。以下是解决方案的代码:
class Counter with StreamMixin
Counter._();
static Counter instance = Counter._();
increment() {
update((lastUpdate ?? 0) + 1);
}
decrement() {
update((lastUpdate ?? 0) - 1);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SO Help'),
),
body: Column(
children:
StreamBuilder
initialData: 0,
stream: Counter.instance.onChange,
builder: (context, snapshot) {
return Text(snapshot.data.toString());
},
),
GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
scrollDirection: Axis.vertical,
children:
InkResponse(
onTap: Counter.instance.increment,
child: const Text("+"),
),
const Sub(),
],
),
],
),
);
}
}
class Sub extends StatelessWidget {
const Sub({Key key});
Widget build(BuildContext context) {
return InkResponse(
onTap: Counter.instance.decrement,
child: const Text("-"),
);
}
}
值得注意的是:
1. 我使用的是StatelessWidget
,这将提高性能。
2. 我使用StreamBuilder
,这将只更新StreamBuilder
中的Text
小部件,而不像setState()
会更新整个应用程序。
3. 逻辑与UI分开。
这是一个有效的解决方案,但不是最佳的。至少可以使用context.ancestorStateOfType
等方法来改进。
以上就是从其他StatefulWidget设置/更新State的问题的原因和解决方法。
在Flutter中,如果想要从一个StatefulWidget的子组件更新另一个StatefulWidget的状态,可以通过以下方法实现:
1. 在子组件中添加一个回调函数参数:
class ChildWidget extends StatefulWidget {
final Function() notifyParent;
ChildWidget({Key key, this.notifyParent}) : super(key: key);
}
2. 在父组件中创建一个用于子组件回调的函数:
refresh() {
setState(() {});
}
3. 在父组件中将父组件的函数传递给子组件:
new ChildWidget(notifyParent: refresh);
4. 在子组件中调用父组件的函数:
widget.notifyParent();
这样就可以从父组件更新子组件的状态了。
如果需要从父组件更新一个有状态的子组件,可以在父组件中存储子组件的引用,并调用子组件的公共方法来更新状态。
如果需要从子组件向父组件传递参数,可以在父组件中定义一个带参数的回调函数,并在子组件中调用该函数并传递参数:
refresh(argument1, argument2) {
setState(() {});
}
widget.notifyParent(1, 2);
以上是一种解决方案,但并不是官方团队提供的解决方法。
如果对此有更好的解决方案,可以在问题的回答中添加新的答案,或者向Flutter团队提出建议,在GitHub上开启一个问题(issue)。如果不知道如何操作,也可以请求帮助,有人会为你完成这个操作。
对于那些想要向子组件传递值的人,可以在父组件中创建一个ValueNotifier,并将其传递给子组件。在子组件中,可以利用ValueListenableBuilder来构建布局。
如果还有问题,请在Stack Overflow上更新问题。