I have this code right here, and what I am trying to do is when I press one of the IconButoons, the text below should change depending on what IconButton was pressed. I have a string variable which is modified in every onPressed function, and this variable is oassed to the Text widget. I made something to happen, but not how I want to. For example, I have to press one IconButton, close the AlertDialog, open it again, and only then see the right text from the IconButton. How can I make that Text appear instantly when I press one of the IconButtons. I will paste the hole class that contains the AlertDialog, this specific part being at the bottom of the class.
class _StartPageState extends State<StartPage> {
bool isLoading = false;
String appRate = '';
@override
Widget build(BuildContext context) => isLoading
?const LoadingPage()
: Scaffold(
bottomNavigationBar: BottomAppBar(
color: Colors.teal[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Spacer(),
IconButton(
splashColor: Colors.lightBlueAccent,
tooltip: 'Help',
icon: const Icon(Icons.info),
iconSize: 25,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => InfoPage()),
);
},
),
const Spacer(),
IconButton(
splashColor: Colors.lightBlueAccent,
tooltip: 'Profile',
icon: const Icon(Icons.account_circle_sharp),
iconSize: 25,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProfilePage()),
);
},
),
const Spacer(),
],
),
),
body: Column(
children: <Widget>[
Image.asset('assets/GameLogo_2.png'),
Container(
height: 100,
),
SizedBox(
width: 170,
height: 80,
child: ElevatedButton(
child: const Text('START!'),
onPressed: () async {
setState(() => isLoading = true);
await Future.delayed(const Duration(seconds: 3));
setState(() => isLoading = false);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Languagele()),
);
},
)
),
Container(
height: 40,
),
SizedBox(
height: 50,
width: 150,
child: ElevatedButton(
onPressed: () {},
child: const Text('Add sentences!', textAlign: TextAlign.center,)
),
),
Container(
height: 20,
),
SizedBox(
height: 50,
width: 150,
child: ElevatedButton(
onPressed: () {
showDialog<String>(
barrierDismissible: false,
context: context,
builder: (BuildContext context) => AlertDialog(
backgroundColor: Colors.teal[50],
title: const Text('Rate the game', textAlign: TextAlign.center, style: TextStyle(fontSize: 25),),
content: SizedBox(
height: 80,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () {
appRate = 'Poor';
setState(() {});
},
icon: const Icon(Icons.star, size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Fair';
setState(() {});
},
icon: const Icon(Icons.star, size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Acceptable';
setState(() {});
},
icon: const Icon(Icons.star, size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Good';
setState(() {});
},
icon: const Icon(Icons.star, size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Outstanding';
setState(() {});
},
icon: const Icon(Icons.star, size: 35, color: Colors.teal),
),
],
),
Text(appRate)
],
)
),
elevation: 24,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
actionsAlignment: MainAxisAlignment.spaceAround,
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Ok'),
),
],
)
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text('Rate the app! '),
Icon(Icons.star)
],
)
),
)
]
),
backgroundColor: Colors.white,
);
}
CodePudding user response:
when you call SetState your screen would change but the dialog would not update, so for that we need to update it manually by wrap your dialog's content with StatefulBuilder , like this:
showDialog<String>(
barrierDismissible: false,
context: context,
builder: (BuildContext context) => AlertDialog(
backgroundColor: Colors.teal[50],
title: const Text(
'Rate the game',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25),
),
content: StatefulBuilder(
builder: (context, innerSetState) {
return SizedBox(
height: 80,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () {
appRate = 'Poor';
setState(() {});
innerSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Fair';
setState(() {});
innerSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Acceptable';
setState(() {});
innerSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Good';
setState(() {});
innerSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Outstanding';
setState(() {});
innerSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
],
),
Text(appRate)
],
));
}),
elevation: 24,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
actionsAlignment: MainAxisAlignment.spaceAround,
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Ok'),
),
],
));
Another tip for cleaner code, try create other widget class and put your dialog builder inside that and pass value like this:
onPressed: () async {
Future<String?> future = showDialog<String>(
barrierDismissible: false,
context: context,
builder: (BuildContext context) =>
YourOtheWidgetClass());
future.then((value) {
if (value != null) {
setState(() {
appRate = value;
setState(() {});
});
}
});
},
and inside you Dialog create variable like appRate and instead of calling setstate to pass it do nothing and pass it through ok button like this:
Navigator.pop(context, appRate);
CodePudding user response:
You have to wrap your AlertDialog inside a StatefulBuilder to update the dialog state.
showDialog<String>(
barrierDismissible: false,
context: context,
builder: (BuildContext context) =>
StatefulBuilder(builder: (context, alertSetState) {
return AlertDialog(
backgroundColor: Colors.teal[50],
title: const Text(
'Rate the game',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25),
),
content: SizedBox(
height: 80,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () {
appRate = 'Poor';
alertSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Fair';
alertSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Acceptable';
alertSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Good';
alertSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
IconButton(
onPressed: () {
appRate = 'Outstanding';
alertSetState(() {});
},
icon: const Icon(Icons.star,
size: 35, color: Colors.teal),
),
],
),
Text(appRate)
],
)),
elevation: 24,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
actionsAlignment: MainAxisAlignment.spaceAround,
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Ok'),
),
],
);
}));