前言:
这是我参与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
的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~