Reputation: 107
I'm new to Flutter/Dart developing but i'm having this issue where calling setState is not rebuilding the widget.
I'm trying to show in the UI the genres picked by the user when tapping on them as well as adding them to another list. The color of the tapped selection is supposed to change yet when reopening the modal nothing changes but the genre is actually added to another list.
Here's the code
class GenresPicker extends StatefulWidget {
@override
_GenresPickerState createState() => _GenresPickerState();
}
class _GenresPickerState extends State<GenresPicker> {
List<Genre> _selectedGenres = [];
@override
void initState() {
super.initState();
}
addGenre(genre) {
setState(() {
_selectedGenres.add(genre);
});
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: FutureBuilder<List<Genre>>(
future: fetchGenres(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"MODAL BOTTOM SHEET EXAMPLE",
style: TextStyle(
fontStyle: FontStyle.italic,
letterSpacing: 0.4,
fontWeight: FontWeight.w600),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return Column(
children: <Widget>[
Text("Genres:"),
Expanded(
child: GridView.builder(
gridDelegate:
SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100,
childAspectRatio: 4 / 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext ctx, index) {
return Container(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
//_selectedGenres
// .add(snapshot.data![index]);
if (!_selectedGenres.contains(
snapshot.data![index])) {
addGenre(snapshot.data![index]);
}
},
child: Text(snapshot.data![index].name),
),
decoration: BoxDecoration(
color: _selectedGenres.contains(
snapshot.data![index])
? Colors.blue[200]
: Colors.blue[50],
borderRadius:
BorderRadius.circular(15)),
);
},
),
),
],
);
},
);
},
child: Text(
'Click Me',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
letterSpacing: 0.6),
),
),
],
),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return Center(child: CircularProgressIndicator());
},
),
);
}
}
The commented code was a workoround that somehow worked better but not the intended result since with it when tapping and reopening the modal the selection is actually shown.
Thanks in advance.
Upvotes: 2
Views: 3941
Reputation: 1428
This happens just because you use setState inside the showModalBottomSheet(Dialog).
Make sure whenever you want to refresh data inside the dialog wrap the child with StatefulBuilder and use that builder's setState to refresh the list it will work.
import 'package:flutter/material.dart';
class BottomRefreshExample extends StatefulWidget {
@override
_BottomRefreshExampleState createState() => _BottomRefreshExampleState();
}
class _BottomRefreshExampleState extends State<BottomRefreshExample> {
List<String> _selectedListData = [];
List<String> _responseListData = ["Add1", "Add2", "Add3", "Add4", "Add5"];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"MODAL BOTTOM SHEET EXAMPLE",
style: TextStyle(fontStyle: FontStyle.italic, letterSpacing: 0.4, fontWeight: FontWeight.w600, fontSize: 12),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setNewState) {
return Column(
children: <Widget>[
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100, childAspectRatio: 4 / 2, crossAxisSpacing: 10, mainAxisSpacing: 10),
itemCount: _responseListData.length,
itemBuilder: (BuildContext ctx, index) {
return Container(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
if (!_selectedListData.contains(_responseListData[index])) {
setNewState(() {
_selectedListData.add(_responseListData[index]);
});
}
},
child: Text(_responseListData[index]),
),
decoration: BoxDecoration(
color: _selectedListData.contains(_responseListData[index]) ? Colors.blue[200] : Colors.blue[50],
borderRadius: BorderRadius.circular(15)),
);
},
),
),
],
);
});
},
);
},
child: Text(
'Open Bottom Sheet',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w600, letterSpacing: 0.6),
),
),
],
),
),
);
}
}
Upvotes: 11