带有分隔符的颤振组列表视图
Posted
技术标签:
【中文标题】带有分隔符的颤振组列表视图【英文标题】:Flutter group listviews with separator 【发布时间】:2018-04-24 07:09:34 【问题描述】:我正在寻找一些指导来创建带有分隔符的列表视图。例如,我想从按日期分组的数据库中获取消息,并按日期用一些图形或线条等分隔消息……然后将消息放在分隔符下。在颤振中尝试这个,任何指导或推动正确的方向将不胜感激。
【问题讨论】:
另见Flutter divider: How could I add divider between each line in my code? 【参考方案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
],
);
【讨论】:
以上是关于带有分隔符的颤振组列表视图的主要内容,如果未能解决你的问题,请参考以下文章