前言:
这是我参与8月更文挑战的第 18 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战,我准备在本月挑选 31 个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录 的重要素材。希望可以坚持下去,你的支持将是我最大的动力~
一、认识 Divider 组件
Divider 组件大家都很熟悉,就是一根水平的分割线,可以指定高度、粗细、颜色、边距。那这些属性默认是什么,如何统一设置默认值,Divider 组件的源码又是如何实现的呢?本文就来详细介绍一下。
1. Divider 基本信息
下面是 Divider 组件类的定义和 构造方法,可以看出它继承自 StatelessWidget。有五个可选参数:
2.Divider 的尺寸分析
先看一下 Divider 的尺寸特点:下面先通过[w(10,200) - h(0,200)] 的约束。Divider 可以通过 height 指定其尺寸区域高度,而宽度是父级约束的最大值。
注: [w(a,b) - h(c,d)] 表示,尺寸约束宽在 a 和 b 之间,高在 c 和 d 之间。
class DividerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 200,
minWidth: 10,
maxHeight: 200,
minHeight: 0
),
child: Divider(
height: 10,
),
);
}
}
当约束改为[w(10,200) - h(50,200)] ,可以看出 Divider 指定的高就会无效。也就是说 Divider 指定的高并非一定生效,它会受到父级区域约束的管控。
class DividerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 200,
minWidth: 10,
maxHeight: 200,
minHeight: 50
),
child: Divider(
height: 10,
),
);
}
}
如果通过 UnconstrainedBox 接触父级的约束,那么 Divider 组件由于宽度没有限制,就不会显示。这也说明了父级的区域约束对 Divider 组件是很重要的。
通过渲染树可以看出,Divider 组件对应的渲染对象最终尺寸为 Size(0,0) ,这也就解释了为什么在无约束的情况下,Divider 组件不会显示。
class DividerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 200,
minWidth: 10,
maxHeight: 200,
minHeight: 50
),
child: UnconstrainedBox(
child: Divider(
height: 10,
),
),
);
}
}
3.Divider 的属性
这些属性的含义都很简单,下面代码是三条分割线。
| 属性名 | 类型 | 默认值 | 用途 |
|---|---|---|---|
| height | double | null | 组件高 |
| thickness | double | null | 线粗细 |
| indent | double | null | 左边距 |
| endIndent | double | null | 右边距 |
| color | Color | null | 线颜色 |
class DividerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 200,
child: Wrap(
children:[
const Divider(
height: 10,
indent: 20,
endIndent: 20,
thickness: 1,
color: Colors.orange,
),
const Divider(
height: 10,
indent: 10,
endIndent: 10,
thickness: 2,
color: Colors.blueAccent,
),
const Divider(
height: 10,
),
],
),
);
}
}
其中 indent 和 endIndent 可以用于类似这样的边距,就不需要额外套 Padding 实现了。
4.Divider 的默认属性
如果一个应用中需要指定默认的 Divider 样式,每次使用都设置一下显然很麻烦。Flutter 中有相关的主题组件 DividerTheme ,其中维护了 DividerThemeData 数据。我们可以通过 该组件使其子节点的 Divider 按照默认样式进行展现。效果如下:
class DividerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DividerTheme(
data: DividerThemeData(
color: Colors.orange,
thickness: 1/window.devicePixelRatio,
space: 5
),
child: Container(
width: 200,
child: Wrap(
children:[
const Divider(),
const Divider(),
const Divider(),
],
),
),
);
}
}
二、 Divider 的源码实现
首先,它是 StatelessWidget,只能依赖于其他组件进行构建,核心逻辑在 build 方法中。
另外注意一下,在构造方法的断言中,四个数字属性都不能为负数。
build 方法也比较简单,首先通过 DividerTheme 获取数据,可以看出如果没有设置主体,默认的高度是 16 逻辑像素。也就是说这时 Divider 本身是有一定的高度占位的。区域尺寸通过 SizedBox 设定,分割线是通过 Container 装饰的底边线完成的。其中 indent 和 endIndent 作用于 margin 属性,本质还是通过 Padding 组件完成的边距。
通过调试可以看出默认 DividerTheme 中的数据属性为 null ,那问题来了 Divider 的默认颜色是什么?
在 createBorderSide 静态方法中,可以看出,如果 DividerTheme 颜色为 null ,会根据 Theme 中的 dividerColor 设置颜色。
那Divider 的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~