Как установить/обновить состояние StatefulWidget из другого StatefulWidget в Flutter?
- Например, в приведенном ниже коде кнопка плюс работает и может обновлятьтекст, но кнопка минус нет.
- Но если мы нажмем FloatingActionButton, то состояние будет обновлено.
- Кнопка минус меняет значение переменной, но не
обновление состояния родительского виджета.
![enter image description here]()
вот код.....
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<MyHomePage> {
@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: <Widget>[
new Text(
number.toString(),
style: textStyle,
),
new GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
scrollDirection: Axis.vertical,
children: <Widget>[
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<Sub> {
@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;
});
},
);
}
}
Ответы
Ответ 1
СТАРЫЙ: создать глобальный экземпляр _MyHomePageState. Используйте этот экземпляр в _SubState как _myHomePageState.setState
NEW: нет необходимости создавать глобальный экземпляр. Вместо этого просто передайте родительский экземпляр дочернему виджету
КОД ОБНОВЛЕН В СООТВЕТСТВИИ С ФЛЕТТОРОМ 0.8.2:
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(),
);
}
}
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 {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int number = 0;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('SO Help'),
),
body: new Column(
children: <Widget>[
new Text(
number.toString(),
style: textStyle,
),
new GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
scrollDirection: Axis.vertical,
children: <Widget>[
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(this),
],
),
],
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
setState(() {});
},
child: new Icon(Icons.update),
),
);
}
}
class Sub extends StatelessWidget {
_MyHomePageState parent;
Sub(this.parent);
@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: () {
this.parent.setState(() {
this.parent.number --;
});
},
);
}
}
Просто дай мне знать, если это работает.
Ответ 2
1. На дочернем виджете: добавьте параметр Function paramter
class ChildWidget extends StatefulWidget {
final Function() notifyParent;
ChildWidget({Key key, @required this.notifyParent}) : super(key: key);
}
2. На родительском виджете: создайте функцию для обратного вызова дочернего элемента
refresh() {
setState(() {});
}
3. На родительском виджете: передайте parentFunction дочернему виджету
new ChildWidget( notifyParent: refresh );
4.На дочернем виджете: вызов родительской функции
widget.notifyParent();
Ответ 3
![enter image description here]()
Этот пример показывает вызов метода
- Определено в дочернем виджете из родительского виджета.
- Определено в родительском виджете из дочернего виджета.
class ParentPage extends StatefulWidget {
@override
_ParentPageState createState() => _ParentPageState();
}
class _ParentPageState extends State<ParentPage> {
final GlobalKey<_ChildPageState> _key = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Parent")),
body: Center(
child: Column(
children: <Widget>[
Expanded(
child: Container(
color: Colors.grey,
width: double.infinity,
alignment: Alignment.center,
child: RaisedButton(
child: Text("Call method in child"),
onPressed: () => _key.currentState.methodInChild(), // calls method in child
),
),
),
Text("Above = Parent\nBelow = Child"),
Expanded(
child: ChildPage(
key: _key,
function: methodInParent,
),
),
],
),
),
);
}
methodInParent() => Fluttertoast.showToast(msg: "Method called in parent", gravity: ToastGravity.CENTER);
}
class ChildPage extends StatefulWidget {
final Function function;
ChildPage({Key key, this.function}) : super(key: key);
@override
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends State<ChildPage> {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.teal,
width: double.infinity,
alignment: Alignment.center,
child: RaisedButton(
child: Text("Call method in parent"),
onPressed: () => widget.function(), // calls method in parent
),
);
}
methodInChild() => Fluttertoast.showToast(msg: "Method called in child");
}
Ответ 4
Я хотел бы расширить ответ мохамеда Эльрашида на тот случай, если вам потребуется передать переменную из дочернего виджета в родительский виджет
На дочернем виджете:
class ChildWidget extends StatefulWidget {
final Function() notifyParent;
ChildWidget({Key key, @required this.notifyParent}) : super(key: key);
}
На родительском виджете
void refresh(dynamic childValue) {
setState(() {
_parentVariable = childValue;
});
}
На родительском виджете: передайте вышеуказанную функцию дочернему виджету
new ChildWidget( notifyParent: refresh );
На дочернем виджете: вызовите родительскую функцию с любой переменной из дочернего виджета
widget.notifyParent(childVariable);