`Hi, I'm trying to show a list of country flags using Flutter, SliverGrid and FutureBuilder.
In the showCountries(), 'childCount: snapshot.data.length' line, getting an error: undefined 'snapshot' and not compiling. If commented out, the list is building good, but adding many additional tiles with 'Another exception was thrown: RangeError (index): Index out of range: index should be less than 14: 15'.
Any help is much appreciated. Thanks.`
class CountryListScreen extends StatelessWidget {
final String prefLang;
const CountryListScreen({super.key, required this.prefLang});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: BackButton(
onPressed: () => Navigator.of(context).pop(),
),
title: const Text(AppConstants.appName),
elevation: 2),
body: SafeArea(
child: CustomScrollView(
slivers: [
showCountries(),
],
),
),
);
}
Widget showCountries() {
return SliverGrid(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return FutureBuilder(
future: fetchCountries(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
} else {
return _buildCountryFlag(snapshot.data[index], context);
}
},
);
},
**childCount: snapshot.data.length,**
));
}
Future<List<Country>> fetchCountries() async {
final response =
await Utilities().consumeApi('/countries?language=$prefLang');
return (json.decode(response.body) as List)
.map((i) => Country.fromJson(i))
.toList();
}
Widget _buildCountryFlag(Country country, BuildContext context) {
return InkWell(
onTap: () {
},
child: _FlagItem(
flag: CountryFlag.fromCountryCode(country.code),
countryCode: country.code,
countryName: country.name),
);
}
}
class _FlagItem extends StatelessWidget {
const _FlagItem(
{required this.flag,
required this.countryCode,
required this.countryName});
final CountryFlag flag;
final String countryCode;
final String countryName;
@override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(height: 10),
Expanded(child: flag),
const SizedBox(height: 8),
Expanded(
child: Text(
countryName,
style: Theme.of(context).textTheme.titleMedium,
),
),
],
);
}
}
I think the problem is the visibility of the snapshot
object.
It is defined in FutureBuilder
but you are trying to use it outside of that block.
I think that the possible solutions can be:
childCount = null
(as reported in documentation: If null, the number of children is determined by the least index for which builder returns null)or
childCount = (await fetchCountries()).length
The second solution will call fetchCountries()
twice but you can solve saving the result in a new variable and using it both in FutureBuilder
and in childCount
.
I hope this will help you! ;)