[英]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.