【Flutter 组件集录】Divider | 8 月更文挑战

3,279 阅读4分钟
前言:

这是我参与8月更文挑战的第 18 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战,我准备在本月挑选 31 个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录 的重要素材。希望可以坚持下去,你的支持将是我最大的动力~

本系列组件文章列表
1.NotificationListener2.Dismissible3.Switch
4.Scrollbar5.ClipPath6.CupertinoActivityIndicator
7.Opacity8.FadeTransition9. AnimatedOpacity
10. FadeInImage11. Offstage12. TickerMode
13. Visibility14. Padding15. AnimatedContainer
16.CircleAvatar17.PhysicalShape18.Divider
19.Flexible、Expanded 和 Spacer 20.Card

一、认识 Divider 组件

Divider 组件大家都很熟悉,就是一根水平的分割线,可以指定高度、粗细、颜色、边距。那这些属性默认是什么,如何统一设置默认值,Divider 组件的源码又是如何实现的呢?本文就来详细介绍一下。


1. Divider 基本信息

下面是 Divider 组件类的定义和 构造方法,可以看出它继承自 StatelessWidget。有五个可选参数:

image-20210818081625700


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 的属性

这些属性的含义都很简单,下面代码是三条分割线。

属性名类型默认值用途
heightdoublenull组件高
thicknessdoublenull线粗细
indentdoublenull左边距
endIndentdoublenull右边距
colorColornull线颜色

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