我正在处理一个扑朔迷离的项目,我不能把整个代码引起其超过500行的代码,因此我将尝试问我的问题,就像我使用imp一样。代码部分。
我有一个有状态的小部件,并且在扩展了类get_queryset()
的有状态小部件内有一些功能
文件State<MusicPlayer>
只需使用一个简单的功能
lib\main.dart
此函数在main类的有状态窗口小部件内。
还有另一个文件class MyAppState extends State<MyApp>{
...
void printSample (){
print("Sample text");
}
...
此文件也有一个有状态的小部件,我可以做点什么,以便在这里调用函数lib\MyApplication.dart
..
printSample()
答案 0 :(得分:26)
您可以通过使用小部件的键来实现
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,
)
通过此键,您可以在状态内部调用任何公共方法
_myKey.currentState.printSample();
答案 1 :(得分:24)
要调用父函数,可以使用回调模式。在此示例中,函数(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的源代码以了解其工作原理。
将来和流是传递状态的另一种选择,也可以用于调用子函数。
但是我真的不推荐它。如果您需要调用子窗口小部件的方法,则很像您的应用程序体系结构存在缺陷。 尝试将状态提升到共同祖先!
答案 2 :(得分:2)
虽然使用回调和 GlobalKey
对简单用例很好,但对于更复杂的设置,它们可能应该被视为反模式,因为它们挂钩到小部件类型并依赖于低级实现逻辑。< /p>
如果您发现自己添加了越来越多的回调/全局键,并且开始变得混乱,那么可能是时候切换到 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()
的控制器,即使用 { {1}} 并且要聆听而不是 StreamController<MyCustomEventType>()
,您可以使用 .stream.asBroadcastStream().listen()
。另见https://api.dart.dev/stable/dart-async/Stream-class.html
有关概述此方法和其他方法的答案,请参阅 Inter Widget communication
答案 3 :(得分:1)
我通过反复试验找到了另一个解决方案,但是它奏效了。
import 'main.dart' as main;
然后将此行添加到onPressed下。
main.MyAppState().printSample();
答案 4 :(得分:1)
如果要调用printSample()函数,可以使用:
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();
...
答案 5 :(得分:1)
您可以尝试一下,它将从Page2
(StatefulWidget
)小部件调用Page1
(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();
}
答案 6 :(得分:0)
此处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)
),
);
}
}
因此,通过使用小工具和父类状态,我们可以调用父类方法。
答案 7 :(得分:0)
我刚刚找到了这个问题的最简单解决方案
显然,您可以创建一个仅包含方法的文件,并且可以直接调用
例如,我想在名为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"),
)
);
}),
),
);
}
}
希望这会有所帮助!如果我误解了您的问题,请告诉我。