I am taking this as a reference to expanding and collapsing of expansion tile-------Flutter - Collapsing ExpansionTile after choosing an item
What I want is if I one
You can use ExpandablePanelList to do perform expand and collapse view. Use expansionCallback to maintain active state to perform expand or collapse. here is the working example
class TestExpandableView extends StatefulWidget {
@override
_TestExpandableViewState createState() => _TestExpandableViewState();
}
class _TestExpandableViewState extends State<TestExpandableView> {
int _activeMeterIndex;
@override
Widget build(BuildContext context) {
return Container(
child: new ListView.builder(
itemCount: 2,
itemBuilder: (BuildContext context, int i) {
return Card(
margin:
const EdgeInsets.fromLTRB(10.0, 15.0, 10.0, 0.0),
child: new ExpansionPanelList(
expansionCallback: (int index, bool status) {
setState(() {
_activeMeterIndex = _activeMeterIndex == i ? null : i;
});
},
children: [
new ExpansionPanel(
isExpanded: _activeMeterIndex == i,
headerBuilder: (BuildContext context,
bool isExpanded) =>
new Container(
padding:
const EdgeInsets.only(left: 15.0),
alignment: Alignment.centerLeft,
child: new Text(
'list-$i',
)),
body: new Container(child: new Text('content-$i'),),),
],
),
);
}),
);
}
}
I think you'll need to track the expansion state of each expansion tile individually. Something like:
Map<String, bool> expansionState = Map();
On initialization, you'll need to specify the keys and whether or not you want the associated expansion tile to show as opened or closed. In my code I have a List for the expansion tile names. On page load, I do the following:
categoryList.forEach((name) {
expansionState.putIfAbsent(name, () => true);
});
Then the builder simply refers to the expansionState:
Widget _buildCategory(String name, List<OrderItem> children) {
return ExpansionTile(
key: PageStorageKey<String>(name),
initiallyExpanded: expansionState[name], // true,
title: RichText(
text: TextSpan(
text: name,
style: TextStyle(
color: Colors.blue[800], fontSize: 16, fontWeight: FontWeight.bold),
children: <TextSpan>[
TextSpan(
text: ' - ' + children.length.toString() + ' items',
style: TextStyle(
color: Colors.grey[800],
fontSize: 16,
fontWeight: FontWeight.normal)),
],
)),
onExpansionChanged: ((newState) {
print(name + ' is now ' + newState.toString());
expansionState[name] = newState;
}),
children: children.map<Widget>(_buildChild).toList(),
);
}
At this point, you have the ability to add a button whose onPressed()
method can manipulate the expansionState map any way you want inside of a setState()
call. You could open them all, close them all, toggle their current states, etc.
Instead of having to maintain the active state in expansionCallback
like @Aravindh Kumar did, you can use ExpansionPanelList.radio
which accepts a list of ExpansionPanelRadio
as its children. This widget allows for at most one panel in the list to be open and maintains the active state for you automatically.
Refer to the flutter documentation for example usage.
// Flutter code sample for ExpansionPanelList.radio
// Here is a simple example of how to implement ExpansionPanelList.radio.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatefulWidget(),
),
);
}
}
// stores ExpansionPanel state information
class Item {
Item({
this.id,
this.expandedValue,
this.headerValue,
});
int id;
String expandedValue;
String headerValue;
}
List<Item> generateItems(int numberOfItems) {
return List.generate(numberOfItems, (int index) {
return Item(
id: index,
headerValue: 'Panel $index',
expandedValue: 'This is item number $index',
);
});
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
List<Item> _data = generateItems(8);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
child: _buildPanel(),
),
);
}
Widget _buildPanel() {
return ExpansionPanelList.radio(
initialOpenPanelValue: 2,
children: _data.map<ExpansionPanelRadio>((Item item) {
return ExpansionPanelRadio(
value: item.id,
headerBuilder: (BuildContext context, bool isExpanded) {
return ListTile(
title: Text(item.headerValue),
);
},
body: ListTile(
title: Text(item.expandedValue),
subtitle: Text('To delete this panel, tap the trash can icon'),
trailing: Icon(Icons.delete),
onTap: () {
setState(() {
_data.removeWhere((currentItem) => item == currentItem);
});
}));
}).toList(),
);
}
}