Flutter 中垂直 ScrollView 内的水平 ListView
Horizontal ListView inside a Vertical ScrollView in Flutter
我正在尝试实现当今非常常见的行为,即在另一个可同时滚动的小部件中有一个水平列表。想像 IMDb 应用程序的主屏幕:
所以我想要一个垂直滚动的小部件,上面只有很少的项目。在它的顶部,应该有一个水平的 ListView
,然后是一些名为 motivationCard
的项目。列表和卡片之间也有一些headers。
我的 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'),
),
],
),
),
);
这是我得到的错误:
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.
我试过:
用 Expanded
小部件包装 ListView
用 SingleChildScrollView > ConstrainedBox > IntrinsicHeight
换行
将 CustomScrollView
作为 parent,将 SliverList
和 SliverChildListDelegate
中的列表
None 这些工作,我继续得到同样的错误。这是一件很常见的事情,应该不难,但我就是无法让它工作:(
非常感谢任何帮助,谢谢!
编辑:
我以为 this 可以帮助我,但没有。
好吧,您的代码可以很好地包装您的- ListView.builder
和 Expanded
小部件 &
Column
小部件的设置 mainAxisSize: MainAxisSize.min,
。
E.x 你所拥有的代码。
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')),
);
},
),
),
],
),
更新:
整个页面可以滚动 - 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')),
),
],
),
),
截图:
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);
}
这样解决了垂直ListView在水平ListView中的问题
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])
]),
)
你也可以这样做 切换到 SingleChildScrollview
中的 Row
:
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")],
),
);
}
},
)
第二个学分是
我们必须在另一个 SingleScrollView
中使用 SingleScrollView
,使用 ListView
将需要固定高度
SingleChildScrollView(
child: Column(
children: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [Text('H1'), Text('H2'), Text('H3')])),
Text('V1'),
Text('V2'),
Text('V3')]))
如果有人收到超出渲染视图端口的错误。在 Container 小部件中扭曲您的 ListView 并为其指定高度和宽度 属性 以解决问题
Column(
children: <Widget>[
Text(
Strings.dailyTasks,
),
Container(
height: 60,
width: double.infinity,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: tasks.length,
itemBuilder: (BuildContext context, int index) =>
taskCard(
taskNumber: index + 1,
taskTotal: tasks.length,
task: tasks[index],
),
),
)
]
)
对于 Web Chome,您必须添加 MaterialScrollBehavior 才能使水平滚动生效。 see() 我演示了如何使用 scrollcontroller 为列表左右设置动画。
import 'package:flutter/gestures.dart';
class MyCustomScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
return MaterialApp(
title: 'Flutter Demo',
scrollBehavior: MyCustomScrollBehavior(),
)
class TestHorizontalListView extends StatefulWidget {
TestHorizontalListView({Key? key}) : super(key: key);
@override
State<TestHorizontalListView> createState() => _TestHorizontalListViewState();
}
class _TestHorizontalListViewState extends State<TestHorizontalListView> {
List<String> lstData=['A','B','C','D','E','F','G'];
final ScrollController _scrollcontroller = ScrollController();
_buildCard(String value)
{
return Expanded(child:Container(
margin: const EdgeInsets.symmetric(vertical: 20.0),
width:300,height:400,child:Card(child: Expanded(child:Text(value,textAlign: TextAlign.center, style:TextStyle(fontSize:30))),)));
}
void _scrollRight() {
_scrollcontroller.animateTo(
_scrollcontroller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
void _scrollLeft() {
_scrollcontroller.animateTo(
0,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
_segment1()
{
return SingleChildScrollView(child:
Expanded(child:
Container(height:300,
width:MediaQuery.of(context).size.width,
child:Row(children: [
FloatingActionButton.small(onPressed: _scrollRight, child: const Icon(Icons.arrow_right),),
Expanded(child:Scrollbar(child:ListView.builder(
itemCount: lstData.length,
controller: _scrollcontroller,
scrollDirection: Axis.horizontal,
itemBuilder:(context,index)
{
return _buildCard(lstData[index]);
})
,),
),
FloatingActionButton.small(onPressed: _scrollLeft, child: const Icon(Icons.arrow_left),),
]))
,
)
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("horizontal listview",)),body:
segment1(),
);
}
}
我试过这段代码并解决了我的问题,希望能解决你的问题。
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
item(),
item(),
item(),
item(),
],
),
),
我正在尝试实现当今非常常见的行为,即在另一个可同时滚动的小部件中有一个水平列表。想像 IMDb 应用程序的主屏幕:
所以我想要一个垂直滚动的小部件,上面只有很少的项目。在它的顶部,应该有一个水平的 ListView
,然后是一些名为 motivationCard
的项目。列表和卡片之间也有一些headers。
我的 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'),
),
],
),
),
);
这是我得到的错误:
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.
我试过:
用
Expanded
小部件包装 ListView用
换行SingleChildScrollView > ConstrainedBox > IntrinsicHeight
将
中的列表CustomScrollView
作为 parent,将SliverList
和SliverChildListDelegate
None 这些工作,我继续得到同样的错误。这是一件很常见的事情,应该不难,但我就是无法让它工作:(
非常感谢任何帮助,谢谢!
编辑:
我以为 this 可以帮助我,但没有。
好吧,您的代码可以很好地包装您的- ListView.builder
和 Expanded
小部件 &
Column
小部件的设置 mainAxisSize: MainAxisSize.min,
。
E.x 你所拥有的代码。
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')),
);
},
),
),
],
),
更新:
整个页面可以滚动 - 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')),
),
],
),
),
截图:
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);
}
这样解决了垂直ListView在水平ListView中的问题
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])
]),
)
你也可以这样做 切换到 SingleChildScrollview
中的 Row
:
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")],
),
);
}
},
)
第二个学分是
我们必须在另一个 SingleScrollView
中使用 SingleScrollView
,使用 ListView
将需要固定高度
SingleChildScrollView(
child: Column(
children: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [Text('H1'), Text('H2'), Text('H3')])),
Text('V1'),
Text('V2'),
Text('V3')]))
如果有人收到超出渲染视图端口的错误。在 Container 小部件中扭曲您的 ListView 并为其指定高度和宽度 属性 以解决问题
Column(
children: <Widget>[
Text(
Strings.dailyTasks,
),
Container(
height: 60,
width: double.infinity,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: tasks.length,
itemBuilder: (BuildContext context, int index) =>
taskCard(
taskNumber: index + 1,
taskTotal: tasks.length,
task: tasks[index],
),
),
)
]
)
对于 Web Chome,您必须添加 MaterialScrollBehavior 才能使水平滚动生效。 see(
import 'package:flutter/gestures.dart';
class MyCustomScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
return MaterialApp(
title: 'Flutter Demo',
scrollBehavior: MyCustomScrollBehavior(),
)
class TestHorizontalListView extends StatefulWidget {
TestHorizontalListView({Key? key}) : super(key: key);
@override
State<TestHorizontalListView> createState() => _TestHorizontalListViewState();
}
class _TestHorizontalListViewState extends State<TestHorizontalListView> {
List<String> lstData=['A','B','C','D','E','F','G'];
final ScrollController _scrollcontroller = ScrollController();
_buildCard(String value)
{
return Expanded(child:Container(
margin: const EdgeInsets.symmetric(vertical: 20.0),
width:300,height:400,child:Card(child: Expanded(child:Text(value,textAlign: TextAlign.center, style:TextStyle(fontSize:30))),)));
}
void _scrollRight() {
_scrollcontroller.animateTo(
_scrollcontroller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
void _scrollLeft() {
_scrollcontroller.animateTo(
0,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
_segment1()
{
return SingleChildScrollView(child:
Expanded(child:
Container(height:300,
width:MediaQuery.of(context).size.width,
child:Row(children: [
FloatingActionButton.small(onPressed: _scrollRight, child: const Icon(Icons.arrow_right),),
Expanded(child:Scrollbar(child:ListView.builder(
itemCount: lstData.length,
controller: _scrollcontroller,
scrollDirection: Axis.horizontal,
itemBuilder:(context,index)
{
return _buildCard(lstData[index]);
})
,),
),
FloatingActionButton.small(onPressed: _scrollLeft, child: const Icon(Icons.arrow_left),),
]))
,
)
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("horizontal listview",)),body:
segment1(),
);
}
}
我试过这段代码并解决了我的问题,希望能解决你的问题。
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
item(),
item(),
item(),
item(),
],
),
),