Horizontal ListView inside a Vertical ScrollView in Flutter
I am trying to achieve a very common behavior nowadays which is to have a horizontal List within another widget that is at the same time scrollable. Think something like the home screen of the IMDb app:
So I want to have a widget that scrolls vertically with few items on them. At the top of it, there should be a horizontal ListView
, followed up with some items called motivationCard
. There are some headers in between the list and the cards as well.
I got something like this on my Widget
:
@override
Widget build(BuildContext context) => BlocBuilder<HomeEvent, HomeState>(
bloc: _homeBloc,
builder: (BuildContext context, HomeState state) => Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Text(
Strings.dailyTasks,
),
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: tasks.length,
itemBuilder: (BuildContext context, int index) =>
taskCard(
taskNumber: index + 1,
taskTotal: tasks.length,
task: tasks[index],
),
),
Text(
Strings.motivations,
),
motivationCard(
motivation: Motivation(
title: 'Motivation 1',
description:
'this is a description of the motivation'),
),
motivationCard(
motivation: Motivation(
title: 'Motivation 2',
description:
'this is a description of the motivation'),
),
motivationCard(
motivation: Motivation(
title: 'Motivation 3',
description:
'this is a description of the motivation'),
),
],
),
),
);
this is the error I get:
I/flutter (23780): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (23780): The following assertion was thrown during performResize():
I/flutter (23780): Horizontal viewport was given unbounded height.
I/flutter (23780): Viewports expand in the cross axis to fill their container and constrain their children to match
I/flutter (23780): their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of
I/flutter (23780): vertical space in which to expand.
I have tried:
-
Wrapping the ListView with an
Expanded
widget -
Wrapping the Column with
SingleChildScrollView > ConstrainedBox > IntrinsicHeight
-
Having
CustomScrollView
as a parent, with aSliverList
and the List within aSliverChildListDelegate
None of these work and I continue getting the same kind of error. This is a very common thing and shouldn't be any hard, somehow I just cannot get it to work :(
Any help would be much appreciated, thanks!
Edit:
I thought this could help me but it didn't.
Well, Your Code Work Fine with wrapping your- ListView.builder
with Expanded
Widget &
setting mainAxisSize: MainAxisSize.min,
of Column
Widget.
E.x Code of what you Have.
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Headline',
style: TextStyle(fontSize: 18),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 15,
itemBuilder: (BuildContext context, int index) => Card(
child: Center(child: Text('Dummy Card Text')),
),
),
),
Text(
'Demo Headline 2',
style: TextStyle(fontSize: 18),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx,int){
return Card(
child: ListTile(
title: Text('Motivation $int'),
subtitle: Text('this is a description of the motivation')),
);
},
),
),
],
),
Update:
Whole page Is Scroll-able with - SingleChildScrollView.
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Headline',
style: TextStyle(fontSize: 18),
),
SizedBox(
height: 200.0,
child: ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 15,
itemBuilder: (BuildContext context, int index) => Card(
child: Center(child: Text('Dummy Card Text')),
),
),
),
Text(
'Demo Headline 2',
style: TextStyle(fontSize: 18),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
Card(
child: ListTile(title: Text('Motivation $int'), subtitle: Text('this is a description of the motivation')),
),
],
),
),
Screenshot:
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: 7,
itemBuilder: (_, i) {
if (i < 2)
return _buildBox(color: Colors.blue);
else if (i == 3)
return _horizontalListView();
else
return _buildBox(color: Colors.blue);
},
),
);
}
Widget _horizontalListView() {
return SizedBox(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (_, __) => _buildBox(color: Colors.orange),
),
);
}
Widget _buildBox({Color color}) => Container(margin: EdgeInsets.all(12), height: 100, width: 200, color: color);
}
We have to use SingleScrollView
inside another SingleScrollView
, using ListView
will require fixed height
SingleChildScrollView(
child: Column(
children: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [Text('H1'), Text('H2'), Text('H3')])),
Text('V1'),
Text('V2'),
Text('V3')]))
To solved the vertical ListView in the horizontal ListView this way
ListView.builder(
itemBuilder: (context, index) =>
Column(children: [
_userProfileLayout(reviewPage.items[index]),
Container(
height: 100,
child:
ListView.builder( scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => Text("dddd")),
),
FadeInImage.assetNetwork(
placeholder: "images/default_review_img.png",
image:
"${reviewPage.items[index].multimedias[0]
.url}"),
_placeLayout(reviewPage.items[index])
]),
)
Also you can do it like this way To Switch to a Row
inside a SingleChildScrollview
:
ListView.builder(
itemCount: 3,
scrollDirection: Axis.vertical,
itemBuilder: (context, position) {
if (position == 0) {
return Container(
child: Text("First rwo"),
);
} else if (position == 1) {
return Container(
child: Text("second rwo"),
);
} else if (position == 2) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [Text("List"), Text("List"), Text("List"), Text("List")],
),
);
}
},
)
Second one credit is Jordan Davies