Flutter 中的垂直滚动视图内的水平列表视图

问题描述 投票:0回答:9

我正在尝试实现一种非常常见的行为,即在另一个可同时滚动的小部件中有一个水平列表。想像 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

    中的列表

这些都不起作用,我继续遇到同样的错误。这是一件很常见的事情,应该不难,但我就是无法让它工作:(

任何帮助将不胜感激,谢谢!

编辑:

我以为可以帮助我,但它没有。

flutter listview flutter-layout horizontal-scrolling vertical-scrolling
9个回答
132
投票

好吧,你的代码可以很好地包装你的 -

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')),
      ),
    ],
  ),
),


54
投票

截图:


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);
}

7
投票

我们必须在另一个

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')]))

4
投票

如果有人得到 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],
             ),
         ),
       )
      ]
)

2
投票

我试过这段代码,我解决了我的问题,希望能解决你想要的问题。

       SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            children: [
              item(),
              item(),
              item(),
              item(),
            ],
          ),
        ),

0
投票

对于 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(),
);
  }
}

0
投票

你只需要固定你的

Listview
的高度(例如将它包裹在
SizedBox
中)。

这是因为在绘制框架之前无法知道您的列表视图的内容。试想一下有数百个项目的列表。没有办法直接知道所有项目中的最大高度。


0
投票

使用 Builder 的垂直 ListView 内的水平 ListView

没有一个答案证明可以解决我的问题,即在垂直 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')
      ],
    );
  },
),

0
投票

尝试使用物理学:BouncingScrollPhysics()

如果您使用的是 ListView - ListView 内的水平滚动 - 垂直滚动,这可能会导致子 Listview 过度滚动的问题。 在这种情况下,对我有用的是我为子 ListView 使用了

physics: BouncingScrollPhysics()
,它提供了良好的弹跳滚动效果并解决了我的错误

© www.soinside.com 2019 - 2024. All rights reserved.