【问题标题】:Flutter: Minimum height on horizontal list viewFlutter:水平列表视图的最小高度
【发布时间】:2018-10-13 19:24:32
【问题描述】:

我正在尝试在 Flutter 中创建一个水平滚动的项目列表,并且我希望该列表仅根据其子项占据必要的高度。通过设计“ListView 试图扩展以适应其横向的可用空间”(来自Flutter docs),我还注意到它占据了视口的整个高度,但有没有办法让它不这样做?理想情况下与此类似(显然行不通):

new ListView(
  scrollDirection: Axis.horizontal,
  crossAxisSize: CrossAxisSize.min,
  children: <Widget>[
    new ListItem(),
    new ListItem(),
    // ...
  ],
);

我意识到做到这一点的一种方法是将ListView 包装在具有固定高度的Container 中。但是,我不一定知道物品的高度:

new Container(
  height: 97.0,
  child: new ListView(
    scrollDirection: Axis.horizontal,
    children: <Widget>[
      new ListItem(),
      new ListItem(),
      // ...
    ],
  ),
);

我能够通过将Row 嵌套在SingleChildScrollViewColumnmainAxisSize: MainAxisSize.min 中来组合出一个“解决方案”。但是,对我来说,这并不是一个解决方案:

new Column(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    new SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: new Row(
        children: <Widget>[
          new ListItem(),
          new ListItem(),
          // ...
        ],
      ),
    ),
  ],
);

【问题讨论】:

  • 同样的问题,你解决了吗?
  • 这个问题还没有解决办法,没有。
  • 谢谢,shrinkWrap 对我不起作用。但是您的代码可以: SingleChildScrollView(scrollDirection: Axis.horizo​​ntal, child: new Row( /* 将您的小部件放在这里*/),) 如果您找到了“更好”的解决方案,请告诉我们!
  • @sindrenm 我喜欢 Column/SingleChildScrollView/Row 组合,我决定从中简单地构建一个 StatelessWidget(我称之为 ScrollableRow)。我认为它可以完成工作,我真的不认为它有问题。我只是将其视为一种明确说明您想要什么的方式,并通过从中构建一个小部件,我可以以简洁明了的方式使用它。
  • 那么,最后,我们不能让水平的ListView有基于孩子身高的高度吗? SingleChildScrollView 基于 ListView 是唯一的选择吗?我真的很想使用ListView,因为它在语义上更正确。

标签: listview dart flutter


【解决方案1】:

类似于 Gene 的回答,但是

  1. 您需要多少小部件并不重要。

  2. 不需要知道小部件的高度

    Widget _horizontalWrappedRow(List data) {
    
     var list = <Widget>[Container(width: 16)]; // 16 is start padding
    
     //create a new row widget for each data element
     data.forEach((element) {
        list.add(MyRowItemWidget(element));
     });
    
     // add the list of widgets to the Row as children
     return SingleChildScrollView(
       scrollDirection: Axis.horizontal,
       child: Row(
         crossAxisAlignment: CrossAxisAlignment.start,
         children: list,
       ),
     );
    

    }

【讨论】:

    【解决方案2】:

    如果您不希望列表视图强制您的小部件适合横轴,请确保将它们放置在 Column() 或 Row() 小部件中,而不是将其直接放置在 listview() 中

    new ListView(
      scrollDirection: Axis.horizontal,
      crossAxisSize: CrossAxisSize.min,
      children: <Widget>[
        Column(
          children:[
        new ListItem(),
        new ListItem(),
           ], 
         )
        
      ],
    );
    

    【讨论】:

      【解决方案3】:

      这与此处提出的问题非常相似:Flutter ListView.builder() widget's cross Axis is taking up the entire Screen height

      我相信 ListViews 要求每个项目都具有相同的交叉轴大小。这意味着在这种情况下,我们无法为每个对象设置唯一的高度,交叉轴大小是固定的。

      如果你想让一个可滚动的高度由孩子自己唯一控制,那么你可以使用一个 SingleChildScrollView 和一个 Row (注意:确保设置滚动方向:Axis.horizo​​ntal)

      import 'package:flutter/material.dart';
      
      final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
      
      void main() {
        runApp(MyApp());
      }
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
            debugShowCheckedModeBanner: false,
            home: Scaffold(
              body: SafeArea(
                child: Container(
                    // height: 100, // no need to specify here
                    color: Colors.white,
                    child: SingleChildScrollView(
                      scrollDirection: Axis.horizontal,
                      child: Row(
                        children: <Widget>[
                          Container(
                            height: 300,
                            width: 300,
                            color: Colors.amber[600],
                            child: const Center(child: Text('Entry A')),
                          ),
                          Container(
                            height: 100,
                            color: Colors.amber[500],
                            child: const Center(child: Text('Entry B')),
                          ),
                          Container(
                            height: 50,
                            width: 100,
                            color: Colors.amber[100],
                            child: const Center(child: Text('Entry C')),
                          ),
                          Container(
                            height: 300,
                            width: 300,
                            color: Colors.amber[600],
                            child: const Center(child: Text('Entry A')),
                          ),
                          Container(
                            height: 100,
                            color: Colors.amber[500],
                            child: const Center(child: Text('Entry B')),
                          ),
                          Container(
                            height: 50,
                            width: 100,
                            color: Colors.amber[100],
                            child: const Center(child: Text('Entry C')),
                          ),
                          Container(
                            height: 300,
                            width: 300,
                            color: Colors.amber[600],
                            child: const Center(child: Text('Entry A')),
                          ),
                          Container(
                            height: 100,
                            color: Colors.amber[500],
                            child: const Center(child: Text('Entry B')),
                          ),
                          Container(
                            height: 50,
                            width: 100,
                            color: Colors.amber[100],
                            child: const Center(child: Text('Entry C')),
                          ),
                          Container(
                            height: 300,
                            width: 300,
                            color: Colors.amber[600],
                            child: const Center(child: Text('Entry A')),
                          ),
                          Container(
                            height: 100,
                            color: Colors.amber[500],
                            child: const Center(child: Text('Entry B')),
                          ),
                          Container(
                            height: 50,
                            width: 100,
                            color: Colors.amber[100],
                            child: const Center(child: Text('Entry C')),
                          ),
                          Container(
                            height: 300,
                            width: 300,
                            color: Colors.amber[600],
                            child: const Center(child: Text('Entry A')),
                          ),
                          Container(
                            height: 100,
                            color: Colors.amber[500],
                            child: const Center(child: Text('Entry B')),
                          ),
                          Container(
                            height: 50,
                            width: 100,
                            color: Colors.amber[100],
                            child: const Center(child: Text('Entry C')),
                          ),
                        ],
                      ),
                    )),
              ),
            ),
          );
        }
      }
      

      【讨论】:

      • 这对我来说是完美的,谢谢
      • :D 很高兴为您提供帮助
      【解决方案4】:

      据我了解,您不能在垂直 ListView 中拥有水平 ListView 并动态设置其高度。如果您的要求允许(无无限滚动、少量元素等),您可以改用 SingleChildScrollView。

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

      【讨论】:

      • 最佳答案
      • 同意(还有 8 个)
      【解决方案5】:

      通过应用上述所有解决方案,尚未找到合适的答案,如果我们不知道高度,这有助于我们设置水平 Listview。在所有情况下,我们都必须设置高度。所以我应用了以下对我有用的解决方案,而没有为列表项指定任何高度。 @sindrenm 在他的问题中已经提到过。所以我想继续使用它,直到找到可行的解决方案。我应用了 shrinkWrap: true 但它会沿主轴收缩 ListView。 (仅适用于垂直滚动视图)而不是沿问题中询问的横轴。所以在不久的将来,任何人都可以在生产中使用这个解决方案,它对我的​​所有水平列表都很有用。

      //below declared somewhere in a class above any method and assume list has filled from some API.
      var mylist = List<myModel>();
      
      
      SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Row(
                children: [
                      for (int index = 0; index < mylist.length; index++) 
                            listItem(mylist[index]);
               ],
              ),
            ),
          ),
      
          listItem(){
            return Column(
               children[
                  widget1(),
                  widget2().... etc..
            ]);
          }
      

      【讨论】:

        【解决方案6】:

        我正在使用容器的水平列表视图构建器,以便停止容器以获取完整高度,我只是用 Center 将它包裹起来,它工作得很好。

        itemBuilder: (context, i){
                      return Center(child: word_on_line(titles[i]));
                  }
        

        【讨论】:

        • 这是一个非常好的解决方案,非常感谢,我想知道为什么我之前没有考虑过:D
        【解决方案7】:

        ColumnmainAxisSize: MainAxisSize.min 包装小部件对我有用。您可以尝试在此处更改height

        var data = [
              {'name': 'Shopping', 'icon': Icons.local_shipping},
              {'name': 'Service', 'icon': Icons.room_service},
              {'name': 'Hotel', 'icon': Icons.hotel},
              {'name': 'More', 'icon': Icons.more}
        ];
        
        new Container(
                constraints: new BoxConstraints(
                  minHeight: 40.0,
                  maxHeight: 60.0,
                ),
                color: Colors.transparent,
                child: new ListView(
                  scrollDirection: Axis.horizontal,
                  children: data
                      .map<Widget>((e) => Column(
                            mainAxisSize: MainAxisSize.min,
                            children: <Widget>[
                              new Container(
                                width: 40,
                                height: 50, // try to change this.
                                color: Colors.transparent,
                                margin: EdgeInsets.only(right: 20, left: 4),
                                child: ClipOval(
                                  child: Container(
                                    padding: EdgeInsets.all(4),
                                    color: Colors.white,
                                    child: Icon(
                                      e["icon"],
                                      color: Colors.grey,
                                      size: 30,
                                    ),
                                  ),
                                ),
                              ),
                            ],
                          ))
                      .toList(),
                ));
        

        【讨论】:

        • 正是我想要的。谢谢!
        【解决方案8】:

        使用扩展

         Expanded(
                child:ListView.separated(
                  shrinkWrap: true,
                padding: EdgeInsets.all(10),
                separatorBuilder: (BuildContext context, int index) {
                  return Align(
                    alignment: Alignment.centerRight,
                    child: Container(
                      height: 0.5,
                      width: MediaQuery.of(context).size.width / 1.3,
                      child: Divider(),
                    ),
                  );
                },
                itemCount: dataMasterClass.length,
                itemBuilder: (BuildContext context, int index) {
        
                  Datum datum = dataMasterClass[index];
                 return sendItem(datum);
        
                },)
              )  ,
        

        【讨论】:

          【解决方案9】:

          使用ConstrainedBox设置minHeightmaxHeight

          ConstrainedBox(
            constraints: new BoxConstraints(
              minHeight: 35.0,
              maxHeight: 160.0,
            ),
          
            child: new ListView(
              shrinkWrap: true,
              children: <Widget>[
                new ListItem(),
                new ListItem(),
              ],
          
            ),
          )
          

          【讨论】:

          • 在不知道列表项的最小/最大高度的情况下如何执行此操作?
          • @sindrenm 你真的需要知道最小/最大高度吗?我的意思是您可以将高度设置在 1 到 1000 之间作为示例,重要的是它将 ListView 的大小调整到所需的高度。如果我遗漏了什么,请告诉我
          • 在我的情况下,ListView 增长到适合 maxHeight,所以不适合。
          • @sindrenm 在这里查看我的答案stackoverflow.com/a/67233853/106941
          【解决方案10】:

          只需将ListViewshrink 属性设置为true,它将适合空间而不是扩展。

          例子:

          ListView(
                  shrinkWrap: true, //just set this property
                  padding: const EdgeInsets.all(8.0),
                  children: listItems.toList(),
                ),
          

          【讨论】:

          猜你喜欢
          • 2019-06-26
          • 2020-11-13
          • 2022-01-17
          • 2020-05-17
          • 2019-12-27
          • 2019-12-20
          • 2019-10-13
          • 1970-01-01
          • 2020-09-26
          相关资源
          最近更新 更多