How to make an Expandable ListView using Flutter like the screenshot below?
I want to make a scrollable list view of ExpansionTiles
which when expanded shows a non-scrollable list view.
I tried to implement list view of ExpansionTiles
inside which I nested another list view using listView.builder(...)
. But when I expanded the ExpansionTile
the list view didn't show up...
(The screenshot is for illustrative purpose)
Is there a way to get similar output in Flutter?
EDIT: My Source Code:
import 'package:flutter/material.dart';
void main() => runApp(
new MaterialApp(
home: new MyApp(),
)
);
var data = {
"01/01/2018": [
["CocaCola", "\$ 5"],
["Dominos Pizza", "\$ 50"],
],
"04/01/2018": [
["Appy Fizz", "\$ 10"],
["Galaxy S9+", "\$ 700"],
["Apple iPhone X", "\$ 999"],
],
};
List<String> dataKeys = data.keys.toList();
String getFullDate(String date) {
List<String> dateSplit = date.split('/');
List<String> months = ["Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"];
return "${dateSplit[0]} ${months[int.parse(dateSplit[1]) - 1]} ${dateSplit[2]}";
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Widget> _buildList(int keyIndex) {
List<Widget> list = [];
for (int i = 0; i < data[dataKeys[keyIndex]].length; i++) {
list.add(
new Row(
children: <Widget>[
new CircleAvatar(
child: new Icon(Icons.verified_user),
radius: 20.0,
),
new Text(data[dataKeys[keyIndex]][i][0])
],
)
);
}
return list;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Expense Monitor"),
),
body: new Container (
child: new ListView.builder(
itemCount: dataKeys.length,
itemBuilder: (BuildContext context, int keyIndex) {
return new Card(
child: new ExpansionTile(
title: new Text(getFullDate(dataKeys[keyIndex])),
children: <Widget>[
new Column(
children: _buildList(keyIndex)
)
]
),
);
}
)
)
);
}
}
Error as shown in Console:
I/flutter (12945): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (12945): The following assertion was thrown during performResize():
I/flutter (12945): Vertical viewport was given unbounded height.
I/flutter (12945): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (12945): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (12945): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (12945): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (12945): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (12945): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (12945): the height of the viewport to the sum of the heights of its children.
I/flutter (12945): When the exception was thrown, this was the stack:
I/flutter (12945): #0 RenderViewport.performResize.<anonymous closure> (package:flutter/src/rendering/viewport.dart:944:15)
I/flutter (12945): #1 RenderViewport.performResize (package:flutter/src/rendering/viewport.dart:997:6)
I/flutter (12945): #2 RenderObject.layout (package:flutter/src/rendering/object.dart:1555:9)
I/flutter (12945): #3 _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:109:13)
......
I/flutter (12945): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (12945): Another exception was thrown: RenderBox was not laid out: RenderViewport#df29c NEEDS-LAYOUT NEEDS-PAINT
Try this:
import 'package:flutter/material.dart';
void main() => runApp(new MaterialApp(home: new MyApp(), debugShowCheckedModeBanner: false,),);
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new ListView.builder(
itemCount: vehicles.length,
itemBuilder: (context, i) {
return new ExpansionTile(
title: new Text(vehicles[i].title, style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic),),
children: <Widget>[
new Column(
children: _buildExpandableContent(vehicles[i]),
),
],
);
},
),
);
}
_buildExpandableContent(Vehicle vehicle) {
List<Widget> columnContent = [];
for (String content in vehicle.contents)
columnContent.add(
new ListTile(
title: new Text(content, style: new TextStyle(fontSize: 18.0),),
leading: new Icon(vehicle.icon),
),
);
return columnContent;
}
}
class Vehicle {
final String title;
List<String> contents = [];
final IconData icon;
Vehicle(this.title, this.contents, this.icon);
}
List<Vehicle> vehicles = [
new Vehicle(
'Bike',
['Vehicle no. 1', 'Vehicle no. 2', 'Vehicle no. 7', 'Vehicle no. 10'],
Icons.motorcycle,
),
new Vehicle(
'Cars',
['Vehicle no. 3', 'Vehicle no. 4', 'Vehicle no. 6'],
Icons.directions_car,
),
];