Reputation: 892
I have implemented a showModalBottomSheet that calls a stateful widget. I would like for the stateful widget to be able to receive data from the showModalBottomSheet call, and, modify it.
Below is my parent class, the one that calls the 'showModalBottomSheet' function:
class _parentClass extends StatelessWidget {
bool testing = false; //This is the variable that I am trying to change.
@override
Widget build(BuildContext context) {
void _callModalBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return Wrap(
children: <Widget>[
Container(
child: myStatefulWidget(testingValue: testing),
),
]);
});
print("Testing Value: $testing");
}
return Column(
children: <Widget>[
FlatButton(
child: Text("my button"),
onPressed: _callModalBottomSheet,
),
],
);
}
}
'myStatefulWidget' is actually another class implemented in a whole new file, thus, its only way to access the 'testing' variable is through its constructor (at least, the only way I know).
I have tried this, but it throws an error:
class myStatefulWidget extends StatefulWidget {
final testingValue;
myStatefulWidget({
this.testingValue,
});
//testingValue = !testingValue; //This line throws an error!
@override
myStatefulWidgetState createState() => myStatefulWidgetState();
}
//...
Thank you very much for your help!
Upvotes: 1
Views: 2717
Reputation: 892
I was able to solve it through 3 steps:
1) creating a function that performs the actual modification of the value in the parent widget (and sending it to the statefulWidget):
class _parentClass extends StatelessWidget {
bool testing = false; //This is the variable that I am trying to change.
void changeTesting(bool newValue){
testing = newValue;
}
@override
Widget build(BuildContext context) {
void _callModalBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return Wrap(
children: <Widget>[
Container(
child: myStatefulWidget(testingValue: testing, changeTesting: changeTesting),
),
]);
});
print("Testing Value: $testing");
}
return Column(
children: <Widget>[
FlatButton(
child: Text("my button"),
onPressed: _callModalBottomSheet,
),
],
);
}
}
2) Receiving that function in the StatefulWidget:
class myStatefulWidget extends StatefulWidget {
final testingValue;
final Function(bool) changeTesting;
myStatefulWidget({
this.testingValue,
this.changeTesting,
});
@override
myStatefulWidgetState createState() => myStatefulWidgetState();
}
And finally 3) call that function when a button is pressed in the state of the statefulwidget.
class myStatefulWidgetState extends State<myStatefulWidget> {
@override
Widget build(BuildContext context) {
return FlatButton(
onPressed: (){widget.changeTesting(!widget.testingValue);Navigator.pop(context);},
child: Icon(Icons.check, color: Colors.white, size: 30.0,),
);
}
}
This particular blog post was very useful: https://alligator.io/flutter/widget-communication/
I also found another methodology that is better suited for when the data needs to be sent to many widgets down the line. The solution is called 'inheritedwidgets'. All these references were helpful (although the solution is quite complex): - The best way to passing data between widgets in Flutter - Flutter: How to correctly use an Inherited Widget? - https://medium.com/flutter-community/simple-ways-to-pass-to-and-share-data-with-widgets-pages-f8988534bd5b - https://medium.com/flutter/managing-flutter-application-state-with-inheritedwidgets-1140452befe1 - https://www.youtube.com/watch?v=pi0X-QWWfIk
Upvotes: 0
Reputation: 27137
You can call setState method in then method of showModalBottomSheet, so new data can be reflected in scree. you have to pass value in navigator.pop method.
Following code help you more to understand.
Full working demo:
class DeleteWidget extends StatefulWidget {
@override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
bool testing = false; //This is the variable that I am trying to change.
@override
Widget build(BuildContext context) {
void _callModalBottomSheet() {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return Wrap(children: <Widget>[
Container(
child: myStatefulWidget(testingValue: testing),
),
]);
}).then((value) {
setState(() {
testing = value;
});
});
print("Testing Value: $testing");
}
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(testing.toString()),
FlatButton(
child: Text("my button"),
onPressed: _callModalBottomSheet,
),
],
),
);
}
}
class myStatefulWidget extends StatefulWidget {
final bool testingValue;
myStatefulWidget({this.testingValue});
@override
_myStatefulWidgetState createState() => _myStatefulWidgetState();
}
class _myStatefulWidgetState extends State<myStatefulWidget> {
bool index;
@override
void initState() {
super.initState();
index = widget.testingValue;
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(index.toString()),
RaisedButton(
child: Text("change counter value"),
onPressed: () {
setState(() {
index = !index;
});
},
),
RaisedButton(
child: Text("close sheet"),
onPressed: () {
Navigator.pop(context, index);
},
)
],
);
}
}
Upvotes: 3