I saw the Widget of the Week at https://www.youtube.com/watch?v=2aJZzRMziJc and copied the code to a State class that I cannot get to work.
class SearchResultsPageState extends State<SearchResultsPage> {
final List<bool> _isOpen = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("test"),
),
body: SingleChildScrollView(
child: ExpansionPanelList(
children: [
ExpansionPanel(
headerBuilder: (context, isExpanded) => const Text('one'),
body: const Text('one onenone'),
isExpanded: _isOpen.isNotEmpty ? _isOpen[0] : false,
),
ExpansionPanel(
headerBuilder: (context, isExpanded) => const Text('two'),
body: const Text('two twontwo'),
isExpanded: _isOpen.isNotEmpty ? _isOpen[1] : false,
),
],
expansionCallback: (i, isOpen) => setState(() {
_isOpen[i] = !isOpen;
}),
),
),
);
}
}
I have breakpoints at:
isExpanded: _isOpen.isNotEmpty ? _isOpen[0] : false,
isExpanded: _isOpen.isNotEmpty ? _isOpen[1] : false,
expansionCallback: (i, isOpen) => setState(() {
_isOpen[i] = !isOpen;
}),
The expansionCallback
gets called on every click of the button but an Error
is thrown and the the isExpanded
property is not re-evaluated. The console shows:
The following RangeError was thrown while handling a gesture:
RangeError (index): Invalid value: Valid value range is empty: 0
And it points to:
_isOpen[i] = !isOpen;
What am I missing or doing wrong?
2
Answers
Because your _isOpen list is empty. Initialise list with default values and it will work for you
For multiple data you can declare it like:
When working with a Widget that highly depends on boundaries like ListView, ExpansionPanel etc. You should be more careful with null/empty values for the boundaries to avoid errors like "RangeError".
REASON FOR ERROR
In this case, your _isOpen is an empty bool list (
final List<bool> _isOpen = [];
). And you are trying to get_isOpen[0]
or_isOpen[1]
if ‘isNotEmpty’.You might be thinking all looks good right? Well NO!!
Dart handles
List[index]
with valid length. While You are trying to get anindex
that didn’t yet exist after you think you already checked for not being empty.SOLUTION
Use
Same reason we use
And not longer
Another way is to use
late
and initialize the_isOpen
later before using it with theExpansionPanel