我正在尝试实现一种非常常见的行为,即在另一个可同时滚动的小部件中有一个水平列表。想像 IMDb 应用程序的主屏幕:
所以我想要一个垂直滚动的小部件,上面只有很少的项目。在它的顶部,应该有一个水平的
ListView
,然后是一些称为motivationCard
的项目。列表和卡片之间也有一些标题。
我的手机上有这样的东西
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
作为父母,有SliverList
和SliverChildListDelegate
中的列表
这些都不起作用,我继续遇到同样的错误。这是一件很常见的事情,应该不难,但我就是无法让它工作:(
任何帮助将不胜感激,谢谢!
编辑:
我以为这可以帮助我,但它没有。
好吧,你的代码可以很好地包装你的 -
ListView.builder
和 Expanded
小部件 &
设置mainAxisSize: MainAxisSize.min,
的Column
小部件。
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);
}
我们必须在另一个
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')]))
如果有人得到 renderview port was exceeded 错误。在 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],
),
),
)
]
)
我试过这段代码,我解决了我的问题,希望能解决你想要的问题。
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
item(),
item(),
item(),
item(),
],
),
),
对于 Web Chome,您必须添加 MaterialScrollBehavior 才能使水平滚动起作用。看(Horizontal listview not scrolling on web but scrolling on mobile)我演示了如何使用 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(),
);
}
}
你只需要固定你的
Listview
的高度(例如将它包裹在SizedBox
中)。
这是因为在绘制框架之前无法知道您的列表视图的内容。试想一下有数百个项目的列表。没有办法直接知道所有项目中的最大高度。
没有一个答案证明可以解决我的问题,即在垂直 ListView 中有一个水平 ListView,同时仍然使用 ListBuilder(这比简单地一次渲染所有子元素的性能更高)。
事实证明这很简单。只需将垂直列表的孩子包裹在一个列中,并检查索引是否为 0(或
index % 3 == 0
)然后呈现水平列表。
似乎工作正常:
final verticalListItems = [];
final horizontalListItems = [];
ListView.builder(
shrinkWrap: true,
itemCount: verticalListItems.length,
itemBuilder: (context, vIndex) {
final Chat chat = verticalListItems[vIndex];
return Column( // Wrap your child inside this column
children: [
// And then conditionally render your Horizontal list
if (vIndex == 0) ListView.builder(itemCount: horizontalListItems.length itemBuilder: (context, hIndex) => Text('Horizontal List $hIndex')),
// Vertical list
Text('Item No. $vIndex')
],
);
},
),
如果您使用的是 ListView - ListView 内的水平滚动 - 垂直滚动,这可能会导致子 Listview 过度滚动的问题。 在这种情况下,对我有用的是我为子 ListView 使用了
physics: BouncingScrollPhysics()
,它提供了良好的弹跳滚动效果并解决了我的错误