[英]Change String value from one stateful widget to another stateful widget
[英]call method in one stateful widget from another stateful widget - Flutter
我有一个正在处理的颤振项目,我不能把整个代码放在 500 多行代码中,所以我会尝试像我使用 imp 一样简单地提出我的问题。 部分代码。
我有一个有状态的小部件,并且在扩展State<MusicPlayer>
的类下的有状态小部件中有一些功能
文件lib\\main.dart
只需采取一个简单的功能,如
class MyAppState extends State<MyApp>{
...
void printSample (){
print("Sample text");
}
...
此函数位于主类中的有状态小部件内。
还有另一个文件lib\\MyApplication.dart
这个文件还有一个有状态的小部件,我可以做些什么,以便我可以在这里调用函数printSample()
..
class MyApplicationState extends State<MyApplication>{
...
@override
Widget build(BuildContext context) {
return new FlatButton(
child: new Text("Print Sample Text"),
onPressed :(){
// i want to cal the function here how is it possible to call the
// function
// printSample() from here??
}
);
}
...
}
要调用父函数,您可以使用回调模式。 在这个例子中,一个函数 ( onColorSelected
) 被传递给孩子。 当按下按钮时,孩子会调用该函数:
import 'package:flutter/material.dart';
class Parent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return ParentState();
}
}
class ParentState extends State<Parent> {
Color selectedColor = Colors.grey;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
color: selectedColor,
height: 200.0,
),
ColorPicker(
onColorSelect: (Color color) {
setState(() {
selectedColor = color;
});
},
)
],
);
}
}
class ColorPicker extends StatelessWidget {
const ColorPicker({this.onColorSelect});
final ColorCallback onColorSelect;
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
RaisedButton(
child: Text('red'),
color: Colors.red,
onPressed: () {
onColorSelect(Colors.red);
},
),
RaisedButton(
child: Text('green'),
color: Colors.green,
onPressed: () {
onColorSelect(Colors.green);
},
),
RaisedButton(
child: Text('blue'),
color: Colors.blue,
onPressed: () {
onColorSelect(Colors.blue);
},
)
],
);
}
}
typedef ColorCallback = void Function(Color color);
内部 Flutter 小部件(如按钮或表单字段)使用完全相同的模式。 如果您只想调用不带任何参数的函数,您可以使用VoidCallback
类型来代替定义您自己的回调类型。
如果您想通知更高级别的父母,您可以在每个层次结构级别重复此模式:
class ColorPickerWrapper extends StatelessWidget {
const ColorPickerWrapper({this.onColorSelect});
final ColorCallback onColorSelect;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20.0),
child: ColorPicker(onColorSelect: onColorSelect),
)
}
}
Flutter 不鼓励从父小部件调用子小部件的方法。 相反,Flutter 鼓励您将子项的状态作为构造函数参数传递。 您只需在父小部件中调用setState
来更新其子部件,而不是调用子部件的方法。
一种替代方法是 Flutter 中的controller
类( ScrollController
、 AnimationController
,...)。 这些也作为构造函数参数传递给子级,它们包含控制子级状态的方法,而无需在父级上调用setState
。 例子:
scrollController.animateTo(200.0, duration: Duration(seconds: 1), curve: Curves.easeInOut);
然后要求孩子们聆听这些变化以更新他们的内部状态。 当然,你也可以实现自己的控制器类。 如果需要,我建议您查看 Flutter 的源代码以了解其工作原理。
期货和流是传递状态的另一种选择,也可用于调用子函数。
但我真的不推荐它。 如果你需要调用子widget的方法,那很像是你的应用架构有缺陷。 尝试将状态向上移动到共同祖先!
您可以通过使用小部件的键来做到这一点
myWidget.dart
class MyWidget extends StatefulWidget {
const MyWidget ({Key key}) : super(key: key);
@override
State<StatefulWidget> createState()=> MyState();
}
class MyState extends State<MyWidget >{
Widget build(BuildContext context){ return ....}
void printSample (){
print("Sample text");
}
}
现在,当使用进myWidget声明GlobalKey作为全球关键
GlobalKey<MyState> _myKey = GlobalKey();
并在创建小部件时传递它
MyWidget(
key : _myKey,
)
通过这个键,你可以调用 state 内的任何公共方法
_myKey.currentState.printSample();
如果你想调用 printSample() func 你可以使用:
class Myapp extends StatefulWidget{
...
MyappState myAppState=new MyappState();
@override
MyappState createState() => myAppState;
void printSample(){
myAppState.printSample();
}
}
class MyAppState extends State<MyApp>{
void printSample (){
print("Sample text");
}
}
...............
Myapp _myapp = new Myapp();
myapp.printSample();
...
我通过反复试验找到了另一个解决方案,但它奏效了。
import 'main.dart' as main;
然后在 onPressed 下添加这一行。
main.MyAppState().printSample();
您可以尝试一下,它会从Page1
( StatefulWidget
) 小部件调用Page2
( StatefulWidget
) 中定义的方法。
class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text("Call page 2 method"),
onPressed: () => Page2().method(),
),
),
);
}
}
class Page2 extends StatefulWidget {
method() => createState().methodInPage2();
@override
_Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> {
methodInPage2() => print("method in page 2");
@override
Widget build(BuildContext context) => Container();
}
虽然使用回调和GlobalKey
对简单的用例很好,但对于更复杂的设置,它们可能应该被视为反模式,因为它们挂钩到小部件类型并依赖于低级实现逻辑。
如果您发现自己添加了越来越多的回调/全局键,并且开始变得混乱,那么可能是时候切换到StreamController
+ StreamSubscription
类的东西了。 通过这种方式,您可以将事件与特定的小部件类型分离,并抽象出小部件间的通信逻辑。
在您的顶级小部件(应用程序级或页面级,取决于您的需要)中创建StreamController
实例,并确保在dispose()
方法中释放它:
class _TopLevelPageState extends State<TopLevelPage> {
StreamController<MyCustomEventType> eventController = StreamController<MyCustomEventType>.broadcast();
// ...
@override
void dispose() {
eventController.close();
super.dispose();
}
}
将eventController
实例作为构造函数参数传递给任何需要侦听事件和/或触发事件的子小部件。
MyCustomEventType
可以是一个枚举(如果您不需要传递额外的数据)或一个带有任何您需要的字段的常规对象,以防您需要在事件上设置额外的数据。
现在,在任何小部件(包括您声明StreamController
的父小部件)中,您都可以通过以下方式触发事件:
eventController.sink.add(MyCustomEventType.UserLoginIsComplete);
要在您的孩子(或父小部件)中设置侦听器,请将以下代码放入initState()
:
class _ChildWidgetState extends State<ChildWidget> {
@override
void initState() {
super.initState();
// NOTE: 'widget' is the ootb reference to the `ChildWidget` instance.
this.eventSubscription = widget.eventController.stream.asBroadcastStream().listen((event) {
if (event == MyCustomEventType.UserLoginIsComplete) {
print('handling LOGIN COMPLETE event ' + event.toString());
} else {
print('handling some other event ' + event.toString());
}
}
@override
void dispose() {
this.parentSubscription.cancel();
super.dispose();
}
}
请注意,如果您覆盖StreamController.done()则您的侦听器将不会触发,因为
done()
替换了您之前设置的任何侦听器。
注意:如果您在两个小部件之间有一对一的通信关系,那么您不需要广播事件风格——在这种情况下,您可以创建没有.broadcast()
的控制器,即使用StreamController<MyCustomEventType>()
并你可以使用.stream.listen()
而不是.stream.asBroadcastStream().listen()
.stream.listen()
。 另见https://api.dart.dev/stable/dart-async/Stream-class.html
有关概述此方法和其他方法的答案,请参阅Inter Widget 通信
这里 HomePage 是父页面, ChildPage 是子页面。 有一种方法叫做 onSelectItem,我们需要从子页面调用它。
class HomePage extends StatefulWidget {
@override HomePageState createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
onSelectItem(String param) {
print(param);
}
@override Widget build(BuildContext context) {
}
}
class ChildPage extends StatefulWidget {
final HomePageState homePageState;
ChildPage({Key key, @required this.homePageState}) : super(key: key);
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends State<ChildPage> {
@override Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
widget.homePageState.onSelectItem("test");
},
child: const Text(
'Click here',
style: TextStyle(fontSize: 20)
),
);
}
}
因此,通过使用小部件和父类状态,我们可以调用父类方法。
我刚刚为这个问题找到了一个最简单的解决方案
显然,您只需创建一个仅包含一个方法的文件,您就可以直接调用它
例如,我想在名为custom_show_bottom_sheet.dart
文件中创建一个 showModalBottomSheet 方法:
import 'package:flutter/material.dart';
customShowBottomSheet(context, Widget child){
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return Wrap(
children: <Widget>[
child,
],
);
});
}
你可以简单地这样称呼它:
import 'package:flutter/material.dart';
import '../custom_show_bottom_sheet.dart';
class TestScreen extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FloatingActionButton(
onPressed: (){
customShowBottomSheet( //A method is called here
context,
Container(
height: 200,
child: Text("This is a test"),
)
);
}),
),
);
}
}
希望这会有所帮助! 如果我误解了您的问题或任何内容,请告诉我。
我正在开发一个扑朔迷离的项目,我无法将整个代码引起其超过500行的代码,因此我将尝试问我的问题,就像使用amp的icn一样简单。 代码部分。
我有一个有状态的小部件,并且在有状态的小部件内的某些类下,扩展了类,扩展了State<MusicPlayer>
文件lib\\main.dart
只是采取一个简单的功能,如
class MyAppState extends State<MyApp>{
...
void printSample (){
print("Sample text");
}
...
此函数位于主类内部的有状态窗口小部件中。
还有另一个文件lib\\MyApplication.dart
这个文件也有一个有状态的小部件,我可以做些什么,以便在这里调用函数printSample()
。
class MyApplicationState extends State<MyApplication>{
...
@override
Widget build(BuildContext context) {
return new FlatButton(
child: new Text("Print Sample Text"),
onPressed :(){
// i want to cal the function here how is it possible to call the
// function
// printSample() from here??
}
);
}
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.