call method in one stateful widget from another stateful widget - Flutter
if you want to call printSample() func you can use:
class Myapp extends StatefulWidget{
...
final 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();
...
To call a function of a parent, you can use the callback pattern. In this example, a function (onColorSelected
) is passed to the child. The child calls the function when a button is pressed:
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);
Internal Flutter widgets like buttons or form fields use exactly the same pattern. If you only want to call a function without any arguments, you can use the VoidCallback
type instead defining your own callback type.
If you want to notify a higher up parent, you can just repeat this pattern on every hierarchy level:
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),
)
}
}
Calling a method of child widget from a parent widget is discouraged in Flutter. Instead, Flutter encourages you to pass down the state of a child as constructor parameters. Instead of calling a method of the child, you just call setState
in the parent widget to update its children.
One alternative approach are the controller
classes in Flutter (ScrollController
, AnimationController
, ...). These are also passed to the children as constructor parameters, and they contain methods to control the state of the child without calling setState
on the parent. Example:
scrollController.animateTo(200.0, duration: Duration(seconds: 1), curve: Curves.easeInOut);
The children are then required to listen to these changes to update their internal state. Of course, you can also implement your own controller class. If you need to, I recommend you to look at the source code of Flutter to understand how that works.
Futures and streams are another alternative to pass down state, and could also be used to call a function of a child.
But I really don't recommend it. If you need to call a method of a child widget, it is very like that your application architecture is flawed. Try to move the state up to the common ancestor!
You can do that by use key of 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");
}
}
now when use MyWidget declare GlobalKey as global key
GlobalKey<MyState> _myKey = GlobalKey();
and pass it when create widget
MyWidget(
key : _myKey,
)
by this key you can call any public method inside state
_myKey.currentState.printSample();