'How to call function from Stateful widget
I have seen many questions similar to mine in Stack Overflow but it did not fit my case since they were asking to call function
from - to Stateful
widget.
I want call function located into State Full
widget from a non Stateful-Stateless Widget
My code is complicated, I will try to explain it below:
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
void myFunction(){
print('hello dart');
}
ShowDialog showDialog = ShowDialog();
@override
Widget build(BuildContext context) {
return TextButton(
onPressed: (){
showDialog.myDialog();
},
child: Text('tab me')
);
}
}
class ShowDialog {
Widget myDialog(){
return showDialog(
builder: (BuildContext context) {
return SimpleDialog(
backgroundColor: Colors.deepPurple[900],
titleTextStyle: const TextStyle(
color: Colors.red, fontSize: 18),
children: [
ElevatedButton(
onPressed: () {
// here i need to call myFunction() Methood
},
child: const Text("tab")
),
],
)
},
);
}
}
How can I go through this?
Solution 1:[1]
you can call it directly like this:
_ExampleState().myFunction();
The full code:
class Example extends StatefulWidget {
const Example ({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<Example > createState() => _ExampleState ();
}
class _ExampleState extends State<Example > {
void myFunction(){
print('hello dart');
}
ShowDialog showDialog = ShowDialog();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: TextButton(
onPressed: (){
showDialog.myDialog(context);
},
child: Text('tab me')
)
);
}
}
class ShowDialog {
Future myDialog(BuildContext context){
return showDialog(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
backgroundColor: Colors.deepPurple[900],
titleTextStyle: const TextStyle(
color: Colors.red, fontSize: 18),
children: [
ElevatedButton(
onPressed: () {
// here i need to call myFunction() Methood
_ExampleState().myFunction();
},
child: const Text("tab")
),
],
);
},
);
}
}
The result:
Solution 2:[2]
So in order to have your showDialog
function call MyFunction
, you need to pass it as if it was a callback.
To do that, first add a Function
callback in your class:
class ShowDialog {
ShowDialog({required this.callback});
VoidCallback callback;
...
}
Then you have to pass the callback when you create the object:
ShowDialog showDialog = ShowDialog(callback: myFunction);
You actually can't do that tho, because this is a class variable, a simple solution is to turn your showDialog
variable into a getter, this means showDialog
will compute again every time you call it, which is not ideal but I don't think it will be terrible for this specific use-case.
ShowDialog get showDialog => ShowDialog(callback: myFunction);
note the get keyword and the =>
instead of an equal sign
EDIT:
You can also pass the callback as part of the myDialog
method, this is probably actually a better idea:
Widget myDialog(VoidCallback callback) {
return showDialog(
builder: (BuildContext context) {
return SimpleDialog(
backgroundColor: Colors.deepPurple[900],
titleTextStyle: const TextStyle(
color: Colors.red, fontSize: 18),
children: [
ElevatedButton(
onPressed: callback,
child: const Text("tab")
),
],
)
},
);
}
Solution 3:[3]
I wrote this function that returns a Dialog in a separate file :
Future myDialog({required BuildContext dialogContext, required Function function}){
return showDialog(
context: dialogContext,
builder: (BuildContext context) {
return SimpleDialog(
backgroundColor: Colors.deepPurple[900],
titleTextStyle: const TextStyle(
color: Colors.red, fontSize: 18),
children: [
ElevatedButton(
onPressed: () {
function();
},
child: const Text("tab")
),
],
);
},
);
}
then I made 2 functions, the first one just print (Hello first function) and the second function print (Hello Second function) and set the state and rebuild the widget tree
I made 2 TextButton: the first TextButton call the myDialog function and pass the firstFunction as a parameter, the second TextButton call the myDialog function and pass the secondFunction as a parameter :
the code :
class ExampleState extends State<Example > {
void firstFunction(){
print('Hello first function');
}
void secondFunction(){
setState(() {
print('Hello Second function');
});
}
@override
Widget build(BuildContext context) {
print('build');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: [
TextButton(
onPressed: (){
myDialog(dialogContext: context, function: firstFunction );
},
child: Text('First Dialog')
),
TextButton(
onPressed: (){
myDialog(dialogContext: context, function: secondFunction );
},
child: Text('Second Dialog')
)
],
),
)
);
}
}
notice that I added a print('build'); so I can know when it rebuild the widget tree
The result:
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ma Jeed |
Solution 2 | h8moss |
Solution 3 | Ma Jeed |