【问题标题】:Flutter : How to add a Header Row to a ListViewFlutter:如何将标题行添加到 ListView
【发布时间】:2018-10-03 19:22:33
【问题描述】:

对 Flutter 非常陌生。我已经能够利用 HTTP 请求数据、构建 ListView、编辑该 List 中的 Row 以及其他基础知识。环境优美。

我已经设法为 ListView 拼凑了一个结构糟糕的 Header...但我知道这是不对的。我无法让标题文本正确排列。

我看到Drawer Class有一个DrawerHeader Class,但是看不到ListView有一个ListViewHeader。

 @override
  小部件构建(BuildContext 上下文){
    返回脚手架(
        应用栏:应用栏(
          标题:文本('联系人'),
          行动:[
            IconButton(icon: Icon(Icons.add_circle),
                onPressed:getCustData
            ),
          ],
        ),
        //身体:
        正文:列(
            孩子们: [
              排(
                  孩子们: [
                    扩展(子:Text('',样式:TextStyle(高度:3.0,fontSize:15.2,fontWeight:FontWeight.bold,))),
                    Expanded(child: Text('First Name', style: TextStyle(height: 3.0, fontSize: 15.2, fontWeight: FontWeight.bold,))),
                    Expanded(child: Text('Last Name', style: TextStyle(height: 3.0, fontSize: 15.2, fontWeight: FontWeight.bold,))),
                    Expanded(child: Text('City', style: TextStyle(height: 3.0, fontSize: 15.2, fontWeight: FontWeight.bold,))),
                    Expanded(child: Text('Customer Id', style: TextStyle(height: 3.0, fontSize: 15.2, fontWeight: FontWeight.bold,))),
                    扩展(子:Text('',样式:TextStyle(高度:3.0,fontSize:15.2,fontWeight:FontWeight.bold,))),
                  ]
              ),

          Expanded(child:Container(
            child: ListView.builder(

              itemCount: data == null ? 0 : data.length,
              itemBuilder: (BuildContext context, int index) {

                return InkWell(
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => APIDetailView(data[index])),
                    );
                  },

                  child: ListTile(                //return new ListTile(
                      onTap: null,
                      leading: CircleAvatar(
                        backgroundColor: Colors.blue,
                        child: Text(data[index]["FirstName"][0]),
                      ),
                      title: Row(
                          children: <Widget>[
                            Expanded(child: Text(data[index]["FirstName"])),
                            Expanded(child: Text(data[index]["LastName"])),
                            Expanded(child: Text(data[index]["Bill_City"])),
                            Expanded(child: Text(data[index]["Customer_Id"])),
                          ]
                      )
                  ),

                );
              }, //itemBuilder

            ),
          ),
        ),
      ]
    )
);

} }

谢谢。

【问题讨论】:

  • 考虑使用DataTable
  • 根据提供的代码,你的标题有6个子元素(列标题);第一个和最后一个是空的。第一个空标题元素由ListTile 中的leading 属性表示,但没有相关的trailing 属性与第6 个空标题列相匹配。因此,标题显示 6 个元素,但您的列表仅占用 5 列(1 个 leading 和一个 title w/4 个子项)。因此,添加trailing 将有助于将它们对齐,但将标题设置为ListItemleadingtrailingtitle 以及4 个元素使其完美;正如你在回答中所做的那样。

标签: flutter listview dart header flutter-layout


【解决方案1】:

通过 itemBuilder 将标题作为第一行返回:

ListView.builder(
    itemCount: data == null ? 1 : data.length + 1,
    itemBuilder: (BuildContext context, int index) {
        if (index == 0) {
            // return the header
            return new Column(...);
        }
        index -= 1;

        // return row
        var row = data[index];
        return new InkWell(... with row ...);
    },
);

【讨论】:

  • 谢谢...我觉得这比我拥有的要干净得多。我仍在努力让 Header 标题与 ListView 列对齐。
  • 你能让每一列的宽度固定吗?
  • 我不喜欢。这是一个移动应用程序......永远不知道我正在处理什么屏幕宽度。
  • 可以从 MediaQuery 中获取屏幕的宽度。用百分比计算宽度怎么样?
  • 不错。我会试一试并回复。
【解决方案2】:

这就是我解决这个问题的方法。感谢 @najeira 让我思考其他解决方案。

在第一个正文列中,我对标题使用了与 ListTile 相同的布局。

因为我的数据ListTile,在这种情况下,包括一个CircleAvatar,所以所有的水平间距都有点偏离......呈现CircleAvatar的5列......然后是4个均匀间隔的列。

所以...我在第一个正文 Column 中添加了一个 ListTile,一个带有透明 backgroundColorCircleAvatar,然后是我的 4 个标题的 Row

        ListTile(
        onTap: null,
        leading: CircleAvatar(
          backgroundColor: Colors.transparent,
        ),
        title: Row(
            children: <Widget>[
              Expanded(child: Text("First Name")),
              Expanded(child: Text("Last Name")),
              Expanded(child: Text("City")),
              Expanded(child: Text("Id")),
            ]
        ),
      ),

【讨论】:

  • 你知道如何让整个东西横向滚动吗?除了我的列表项更大之外,我面临着与标题相同的问题,我在表格中有 10 列,并且想让整个内容也可以横向滚动
  • 您可以将整个内容包装在 ListView 中,并将滚动方向设置为水平。
  • @Abbas.M 用 ```SingleChildScrollView`` 包裹标题:Row(...) ,它将滚动
【解决方案3】:

您可以在Column 中添加ContainerListView

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text("Demo App1"),
        ),
        body: Column(
          children: <Widget>[
            Container(
              height: 40.0,
              child: Row(
                children: <Widget>[
                  Container(
                      padding: EdgeInsets.all(4.0),
                      width: 100.0,
                      child: Text(
                        "Name",
                        style: TextStyle(fontSize: 18),
                      )),
                  Container(
                      padding: EdgeInsets.all(4.0),
                      width: 100.0,
                      child: Text(
                        "Age",
                        style: TextStyle(fontSize: 18),
                      )),
                ],
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: 100,
                itemBuilder: (BuildContext context, int index) {
                  return Row(
                    children: <Widget>[
                      Container(
                          padding: EdgeInsets.all(4.0),
                          width: 100.0,
                          child: Text(
                            "Name $index",
                            style: TextStyle(fontSize: 18),
                          )),
                      Container(
                        padding: EdgeInsets.all(4.0),
                        width: 100.0,
                        child: Text(
                          "Age $index",
                          style: TextStyle(fontSize: 18),
                        ),
                      )
                    ],
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

【讨论】:

  • 我在使用 ListView 时遇到了“A RenderFlex 在底部溢出 69 像素”的问题,这个问题帮助了我。这里的技巧是将 ListView 包装在 Expanded 小部件中。当我使用 SingleChildScrollView 时不起作用,因为我想要不可滚动的标题和可滚动的列表。
【解决方案4】:

您可以像这样向项目列表中的第一项添加一列

  new ListView.builder(
    itemCount: litems.length,
    itemBuilder: (BuildContext ctxt, int index) {
      if (index == 0) {
        return Column(
          children: <Widget>[
            Header(),
            rowContent(index),
          ],
        );
      } else {
        return rowContent(index);
      }
    },
  )

【讨论】:

  • 是的,这非常简单直接。不过,我会说,现在这让我想尝试让它成为一个粘性标题。 :-)
  • 好主意。简单易用。
【解决方案5】:

najeira 的解决方案简单易行,但您可以在不触及索引的情况下获得相同且更灵活的结果。

您可以使用 CustomScrollView & SliverList 来代替 listView,这在功能上与 listView 相同。

   return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverToBoxAdapter(
            // you could add any widget
            child: ListTile(
              leading: CircleAvatar(
                backgroundColor: Colors.transparent,
              ),
              title: Row(
                children: <Widget>[
                  Expanded(child: Text("First Name")),
                  Expanded(child: Text("Last Name")),
                  Expanded(child: Text("City")),
                  Expanded(child: Text("Id")),
                ],
              ),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) {
                return InkWell(
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => APIDetailView(data[index])),
                    );
                  },
                  child: ListTile(
                    //return  ListTile(
                    leading: CircleAvatar(
                      backgroundColor: Colors.blue,
                      child: Text(data[index]["FirstName"][0]),
                    ),
                    title: Row(
                      children: <Widget>[
                        Expanded(child: Text(data[index]["FirstName"])),
                        Expanded(child: Text(data[index]["LastName"])),
                        Expanded(child: Text(data[index]["Bill_City"])),
                        Expanded(child: Text(data[index]["Customer_Id"])),
                      ],
                    ),
                  ),
                );
              },
              childCount: data == null ? 0 : data.length,
            ),
          ),
        ],
      ),
    );

【讨论】:

    【解决方案6】:

    看来您真正在寻找的是 DataTable 小部件而不是 ListView。 它有一个可自定义的标题,包括排序选项。

    阅读文档,包括 api.flutter.dev 上的一些很好的示例:Data Table CLass

    【讨论】:

      【解决方案7】:

      我创建了listview_utils 包来减少构建页眉和页脚列表项所需的样板代码。以下是使用该包的示例代码:

      import 'package:listview_utils/listview_utils.dart';
      
      CustomListView(
        header: Container(
          child: Text('Header'),
        ),
        itemCount: items.length,
        itemBuilder: (BuildContext context, int index, _) {
          return ListTile(
            title: Text(item['title']),
          );
        },
      );
      

      我正在维护这个包。

      【讨论】:

        【解决方案8】:

        使用DataTable 小部件!
        该小部件允许您构建表格。 代码: DataTable(columns: [], rows: [],)

        示例:

          DataTable(
           columns: [
             DataColumn(label: Text('Lang.')),
             DataColumn(label: Text('Year')),
           ],
           rows: [
             DataRow(cells: [DataCell(Text('Dart')), DataCell(Text('2010'))]),
             DataRow(cells: [DataCell(Text('Go')), DataCell(Text('2009'))]),
             DataRow(cells: [DataCell(Text('PHP')), DataCell(Text('1994'))]),
             DataRow(cells: [DataCell(Text('Java')), DataCell(Text('1995'))]),
           ],
        )
        

        输出:

        您可以通过观看此official video 或访问flutter.dev 了解有关DataTable 的更多信息

        【讨论】:

          【解决方案9】:

          在这个代码示例中,我们正在研究如何在列表视图中添加节标题行。

          class HeaderRowListView extends StatelessWidget {
            final List<int> _listData = List<int>.generate(100, (i) => i);
            @override
            Widget build(BuildContext context) {
              return Scaffold(
                appBar: AppBar(
                  title: Text('ListView Header Row'),
                ),
                body: ListView(
                  padding: EdgeInsets.all(8.0),
                  children: _listData.map((i) {
                    return i % 10 == 0
                        ? Container(
                      color: Colors.grey.withOpacity(.5),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        mainAxisSize: MainAxisSize.max,
                        children: <Widget>[
                          Text("Header",
                              style: TextStyle(
                                fontSize: 20.0,
                                fontWeight: FontWeight.bold,
                              )),
                          Text("Feb 26th, 2019",
                              style: TextStyle(
                                fontSize: 14.0,
                                color: Colors.black45,
                              )),
                        ],
                      ),
                      padding: EdgeInsets.all(10.0),
                    )
                        : ListTile(
                      title: Text("Item $i"),
                    );
                  }).toList(),
                ),
              );
            }
          }
          

          【讨论】:

            【解决方案10】:

            我用这个:

            body: Column(
                  children: [
                    Container(
                      // The header will be here
                    ),
                    Expanded(
                      // The ListView
                      child: ListView.builder(
                          itemCount: // The length,
                          itemBuilder: (_, index) {
                            return //List Item Widget Here
                          }),
                    ),
                  ],
            

            )

            【讨论】:

              【解决方案11】:

              通过 itemBuilder 将标题作为第一行返回:

              ListView.builder(
                  itemCount: data == null ? 1 : data.length + 1,
                  itemBuilder: (BuildContext context, int index) {
                      if (index == 0) {
                          // return the header
                          return new Column(...);
                      }
                      index -= 1;
              
                      // return row
                      var row = data[index];
                      return new InkWell(... with row ...);
                  },
              );```
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-10-11
                • 1970-01-01
                • 1970-01-01
                • 2018-01-21
                • 2022-01-09
                相关资源
                最近更新 更多