App开发中,列表的使用是比较常见的场景,Android原生开发时,ListView 是最常用的滑动组件,后来 Google 又推出了功能更加强大,使用更加灵活的 RecyclerView。同样,在 Flutter 开发中,系统也提供了 ListView 用于实现列表滑动的滑动组件,它可以沿一个方向线性排布所有子组件,并且支持基于 Sliver 的延迟构建模型。
Flutter 中使用 ListView 时,如何更有效的设置 Item 项间距呢?
看官方文档,可以找到,我们在构建 ListView 时有四种方式可以使用:
关于上述四种方法的使用,这里不再具体讲述,后面我给出示例代码的地址;
下面就来回答一下,ListView 如果更有效的设置 Item 项间距?
首先滑动方向是竖直方向时如何设置 Item 项间距:
Expanded(
child: RepaintBoundary(
child: ListView.separated(
itemBuilder: (context, index) {
return _CommonItem(stringItem: _words[index]);
},
scrollDirection: Axis.vertical,
padding: _listVerticalPadding,
physics: BouncingScrollPhysics(),
separatorBuilder: (BuildContext context, int index) =>
Divider(
height: 16.0,
color: Color(0xFFFFFFFF),
),
itemCount: _words.length),
),
),
接下来滑动方向是水平方向是如何设置 Item 项间距:
Container(
constraints: BoxConstraints(maxHeight: 100.0, minHeight: 0),
child: ListView.separated(
itemBuilder: (context, index) {
return _CommonItem(stringItem: _words[index]);
},
scrollDirection: Axis.horizontal,
padding: _listHorizontalPadding,
physics: BouncingScrollPhysics(),
separatorBuilder: (BuildContext context, int index) =>
VerticalDivider(
width: 16.0,
color: Color(0xFFFFFFFF),
),
itemCount: _words.length),
),
上面使用到的 Divider 和 VerticalDivider 都是系统提供的,当然我们也可以使用自定义的 分割符子项:
Container(
constraints: BoxConstraints(maxHeight: 100.0, minHeight: 0),
child: ListView.separated(
itemBuilder: (context, index) {
return _CommonItem(stringItem: _words[index]);
},
scrollDirection: Axis.horizontal,
padding: _listHorizontalPadding,
physics: BouncingScrollPhysics(),
separatorBuilder: (BuildContext context, int index) =>
Container(
width: 16.0,
color: Color(0xFFFFFFFF),
),
itemCount: _words.length),
),
是不是很简单啦,查看系统提供的 Divider 和 VerticalDivider 的源代码,会发现它们也只是封装组合了一下系统已有的 Widget 而已,下面看一下 Divider 的源码:
/// Creates a material design divider.
class MyDivider extends StatelessWidget {
const MyDivider({
Key key,
this.height,
this.thickness,
this.indent,
this.endIndent,
this.color,
}) : assert(height == null || height >= 0.0),
assert(thickness == null || thickness >= 0.0),
assert(indent == null || indent >= 0.0),
assert(endIndent == null || endIndent >= 0.0),
super(key: key);
/// 水平分割器的高度值,都不设置,默认为:16.0
final double height;
/// 分割器内绘制的线的厚度
final double thickness;
/// 分割器内绘制的线距离前边缘的空间
final double indent;
/// 分割器内绘制的线距离后边缘的间距
final double endIndent;
/// 分割器内绘制的线的颜色值
final Color color;
/// 创建并计算分割器的边界
static BorderSide createBorderSide(BuildContext context, { Color color, double width }) {
final Color effectiveColor = color
?? (context != null ? (DividerTheme.of(context).color ?? Theme.of(context).dividerColor) : null);
final double effectiveWidth = width
?? (context != null ? DividerTheme.of(context).thickness : null)
?? 0.0;
// Prevent assertion since it is possible that context is null and no color
// is specified.
if (effectiveColor == null) {
return BorderSide(
width: effectiveWidth,
);
}
return BorderSide(
color: effectiveColor,
width: effectiveWidth,
);
}
@override
Widget build(BuildContext context) {
final DividerThemeData dividerTheme = DividerTheme.of(context);
final double height = this.height ?? dividerTheme.space ?? 16.0;
final double thickness = this.thickness ?? dividerTheme.thickness ?? 0.0;
final double indent = this.indent ?? dividerTheme.indent ?? 0.0;
final double endIndent = this.endIndent ?? dividerTheme.endIndent ?? 0.0;
/// 组合一些系统 Widget 来实现
return SizedBox(
// 分割器的高度
height: height,
child: Center(
child: Container(
// 分割器内绘制分割线的厚度
height: thickness,
// 分割器内绘制的分割线距离前后边缘的间距
margin: EdgeInsetsDirectional.only(start: indent, end: endIndent),
decoration: BoxDecoration(
border: Border(
bottom: createBorderSide(context, color: color, width: thickness),
),
),
),
),
);
}
}
完整实例代码可点击进入查看,读者可以试着运行一下,查看具体效果;