【问题标题】:Flutter group listviews with separator带有分隔符的颤振组列表视图
【发布时间】:2018-04-24 07:09:34
【问题描述】:

我正在寻找一些指导来创建带有分隔符的列表视图。例如,我想从按日期分组的数据库中获取消息,并按日期用一些图形或线条等分隔消息……然后将消息放在分隔符下。在颤振中尝试这个,任何指导或推动正确的方向将不胜感激。

【问题讨论】:

标签: flutter


【解决方案1】:

我为设计的丑陋道歉,但只是为了向您展示,您几乎可以构建自己想要的设计,这是一个简单的示例:

import "package:flutter/material.dart";
import 'package:meta/meta.dart';

class Test extends StatefulWidget {
  @override
  _TestState createState() => new _TestState();
}

class _TestState extends State<Test> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Test"),
      ),
      body: new ListView.builder(
        // itemCount: myData.lenght(),
          itemCount: 20,
          itemBuilder: (BuildContext context, int index) {
            //sort my data by timestamp before building
            return new CustomWidget(date: "Convert my time stamp to date",
              content: "My Awesome Content",
              trailingIconOne: new Icon(Icons.share, color: Colors.blueAccent,),
              trailingIconTwo: new Icon(
                Icons.favorite, color: Colors.redAccent,),);
          }),
    );
  }
}

class CustomWidget extends StatelessWidget {
  String date;
  String content;

  Icon trailingIconOne;

  Icon trailingIconTwo;

  CustomWidget(
      {@required this.date, @required this.content, @required this.trailingIconOne, @required this.trailingIconTwo});

  @override
  Widget build(BuildContext context) {
    return new Container(
      decoration: new BoxDecoration(
          border: new Border.all(color: Colors.grey[500])
      ),
      child: new Column(
        children: <Widget>[
          new Container (child: new Text(date), color: Colors.yellow[200],),
          new Container(height: 15.0,),
          new Text(content),
          new Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              new IconButton(icon: trailingIconOne, onPressed: () {}),
              new Container(width: 10.0,),
              new IconButton(icon: trailingIconTwo, onPressed: () {})
            ],
          )
        ],
      ),
    );
  }
}

为了更好的设计,您可以去掉边框并改用Divider

return new Container(
      child: new Column(
        children: <Widget>[
          new Column (children: <Widget>[
            new Container (child: new Text(date), color: Colors.yellow[200],),
            new Container(height: 15.0,),
            new Text(content),
            new Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                new IconButton(icon: trailingIconOne, onPressed: () {}),
                new Container(width: 10.0,),
                new IconButton(icon: trailingIconTwo, onPressed: () {}),
          ], ),

              new Divider(height: 15.0,color: Colors.red,),
            ],
          )
        ],
      ),

我认为更好的视觉解决方案是使用Card而不是Container

return new Card(
      child: new Column(
        children: <Widget>[
          new Column (children: <Widget>[
            new Container (child: new Text(date), color: Colors.yellow[200],),
            new Container(height: 15.0,),
            new Text(content),
            new Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                new IconButton(icon: trailingIconOne, onPressed: () {}),
                new Container(width: 10.0,),
                new IconButton(icon: trailingIconTwo, onPressed: () {}),
          ], ),

            //  new Divider(height: 15.0,color: Colors.red,),
            ],
          )
        ],
      ),
    );

【讨论】:

  • 谢谢,我认为这足以让我朝着正确的方向开始。如果我在路上遇到困难,我会发布一个新项目。
  • 无论如何,我并不打算展示一个伟大的设计,是的,Divider 更好,但只是在这个特定的布局中,它需要调整才能产生效果。我在最后添加了更改,如果我们使用 Card 而不是 Container 作为父级,可能会更好看设计,但这个示例只是为了展示您可以自定义自己的小部件。
  • 似乎我可以毫无问题地静态地做到这一点,我需要看到最好的方法是拉数据和排序。我是拉日期,然后在日期分隔符之后的每个小部件中拉出与该日期相关的消息,还是拉出所有数据并拉出我需要的日期的数据。我已经按照日期顺序将其作为单个列表视图完成,但希望转换为将特定日期的所有消息都放在分隔符下方。想法?还是我应该在这里问另一个问题以获得答案?
  • 也许会问另一个问题以使其更清楚,通常您希望将时间戳存储在数据项本身中,我不确定这是否清楚。另一件事,如果您使用的是 Firebase rtdb,如果您的数据提取是分层的,则可以只使用 FirebaseAnimatedList 而不是 ListView,并且它提供了一个您可以使用的排序参数。
  • 我正在使用 mysql 存储带有 JSON 字段的数据,并为可搜索和可索引字段生成列,这是客户对 DB 的要求。可能就像为唯一日期调用 restapi 一样容易,然后创建分隔符,然后调用数据,因为小部件是为该日期的消息列表视图构建的。如果我被阻止,我会创建一个问题。再次感谢
【解决方案2】:

虽然这可能不适用于您的情况,但将分隔线添加到 ListView 的一种简单方法是使用 ListView.divideTiles

// Adapted from https://flutter.io/flutter-for-android/#listviews--adapters

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new ListExamplePage(),
    );
  }
}

class ListExamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // https://docs.flutter.io/flutter/material/ListTile/divideTiles.html
    var dividedWidgetList = ListTile.divideTiles(
        context: context,
        tiles: _getListData(),
        color: Colors.black).toList();

    return new Scaffold(
      appBar: new AppBar(
        title: new Text('List Example'),
      ),
      body: new ListView(children: dividedWidgetList)
    );
  }

  _getListData() {
    List<Widget> widgets = [];
    for (int i=0; i<100; i++) {
      widgets.add(
        new Padding(
            padding: new EdgeInsets.all(10.0),
            child: new Text('Row $i'))
      );
    }
    return widgets;
  }
}

编辑:

对于动态构建的列表,ListTile.divideTiles 不是正确的选择。在构建列表项的阶段添加分隔符可能是最好的方法:

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new ListExamplePage(),
    );
  }
}

class ListExamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('List Example'),
        ),
        body: new ListView.builder(
          itemBuilder: (BuildContext context, int position) =>
              // Try using either _getRowWithDivider or _getRowWithBoxDecoration
              // for two different ways of rendering a divider
              _getRowWithDivider(position),
        ));
  }

  /// Returns the widget at position i in the list, separated using a divider
  Widget _getRowWithDivider(int i) {
    var children = <Widget>[
      new Padding(padding: new EdgeInsets.all(10.0), child: new Text('Row $i')),
      new Divider(height: 5.0),
    ];

    return new Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: children,
    );
  }

// Returns the widget at position i in the list, separated using a BoxDecoration
  Widget _getRowWithBoxDecoration(int i) {
    return new Container(
        decoration: new BoxDecoration(
            border:
                new Border(bottom: new BorderSide(color: Colors.grey[100]))),
        child: new Padding(
            padding: new EdgeInsets.all(10.0), child: new Text('Row $i')));
  }
}

【讨论】:

  • 这看起来很有希望,如果我通过 http 调用获取我的消息列表,你将如何继续,我将它放在一个列表中,现在我使用 listview.builder 并为每个项目应用一个小部件,但现在我想要一个按日期划分的分隔符,每个日期可以是 1 个或多个。我现在正在尝试做一个具有消息列表视图的分隔线列表视图,但与大小错误等作斗争。您的解决方案看起来更直接地接受日期所需的分隔线,而不是每个分隔线。任何建议都会很棒。
  • 对于动态列表,很遗憾 ListTile.divideTiles 不适合您。我建议在构建每行小部件时使用 aziza 的建议并插入 Divider(或 BoxDecoration)。我将更新一个不同的代码 sn-p 来演示。
【解决方案3】:

只需将ListItem 放入Container 并添加装饰:

  @override
  Widget build(BuildContext context) {
    return new Container(
        child: new ListTile(
          title: new Text('I have border')
        ),
        decoration:
            new BoxDecoration(
                border: new Border(
                    bottom: new BorderSide()
                )
            )
        );
  }

【讨论】:

  • 这更简洁,更容易理解,恕我直言
  • 当然,但它会在最后一个元素的底部放置一个边框。这不是正确的做法。
  • @Tony 不一定“不是正确的做法”。如果 listtiles 被循环,检查是否最后一个索引,并且不显示边框。如果手动做listtile,不要在最后一项上添加边框。
【解决方案4】:
final Iterable<ListTile> products = widget.products.map((Product product) {
  return productListAdapter(
    product: product,
  ).build(context);
});

final listView = ListTile.divideTiles(
        context: context, tiles: products, color: Colors.black12)
    .toList();

return ListView(
    padding: EdgeInsets.symmetric(vertical: 8.0), children: listView);

productListAdapter 代码在这里

class productListAdapter extends StatelessWidget {
   final Product product;  
   productListAdapter({this.product});

   TextStyle getTextStyle() {
       return TextStyle(
           fontSize: 16.0,
           color: Colors.black);
   }

   Color getColor(BuildContext context) {
       return Theme.of(context).primaryColor;
     }
   }

   @override
   Widget build(BuildContext context) {
     return ListTile(
       title: Text(product.name),
       leading: CircleAvatar(
         child: Text(
           product.name[0],
           style: getTextStyle(),
         ),
         backgroundColor: getColor(context),
       ),
     );
   }
 }

【讨论】:

    【解决方案5】:

    一个更清洁和简单的解决方案是使用以下

    ListView.separated(
      separatorBuilder: (context, index) => Divider(
            color: Colors.black,
          ),
      itemCount: 20,
      itemBuilder: (context, index) => Padding(
            padding: EdgeInsets.all(8.0),
            child: Center(child: Text("Index $index")),
          ),
    )
    

    【讨论】:

      【解决方案6】:

      这里有很多过于复杂的答案

      只需使用divideTiles:

      new ListView(
                    children: ListTile.divideTiles(context: context, tiles:
      

      或者使用分隔符:

      new ListView.separated(
                    itemCount: 25,
                    separatorBuilder: (BuildContext context, int index) => Divider(),
                    itemBuilder: (BuildContext context, int index) {
      

      【讨论】:

      • ListView.builder 呢?
      【解决方案7】:

      长答案短

      只需使用Column 并添加Divider

      ListView.builder(
            itemCount: count,
            itemBuilder: (context, int index) {return tile(index);},
          ),
      

      为 itemBuilder 创建一个小部件

      Widget tile(int index) {
      return Column(
        children: <Widget>[
          // your widgets in listView
          Divider(),    //at last simply add divider
        ],
      );
      

      }

      【讨论】:

        猜你喜欢
        • 2020-11-15
        • 2021-06-06
        • 2020-09-09
        • 2020-08-14
        • 1970-01-01
        • 2020-06-19
        • 2020-05-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多