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

2022-03-18 15:50:32 浏览数 (1)

1.认识 DecoratedBox 组件

DecoratedBox 组件可能单独使用的频率不是很高,因为它被集成在了 Container 组件中,但装饰的使用方式是共通的,源码中说 DecoratedBox 会在其孩子的前景或背景上绘制 Decoration 装饰对象。这说明 Decoration 才是装饰的重点,我们需要了解或自定义 Decoration

下面是 DecoratedBox 组件类的定义构造方法,可以看出它继承自 SingleChildRenderObjectWidget 。构造时必须传入尺寸 decoration 参数,可以传入 position 入参。

decoration 成员的类型是 Decoration ,表示装饰对象。position 成员的类型是 DecorationPosition 枚举,表示在前景绘制还是在背景绘制。

代码语言:javascript复制
final Decoration decoration;
final DecorationPosition position;

enum DecorationPosition {
  background,
  foreground,
}
2.认识 Decoration 及其子类

首先需要注意的是: Decoration 是一个抽象类,无法直接实例化使用。

Flutter 框架中提供了四个实现类,其中 BoxDecoration 是我们最常用的。

比如下面通过 BoxDecorationborderRadius 可以指定装饰的圆角,通过 color 指定填充的颜色。

代码语言:javascript复制
DecoratedBox(
  decoration: BoxDecoration(
      color: Colors.orangeAccent,
      borderRadius: BorderRadius.only(
          topLeft: Radius.circular(20),
          bottomRight: Radius.circular(20),
        bottomLeft: Radius.circular(5),
        topRight: Radius.circular(5),
      ),
  ),
  child: buildContent(),
);

Widget buildContent() {
  return SizedBox(
    width: 80,
    height: 80,
    child: Icon(Icons.android, size: 50, color: Colors.white),
  );
}

下面是 BoxDecoration 的构造方法,可以看出除了圆角和颜色,还有很多入参,比如背景图片边线阴影渐变形状等。

如下装饰,有红色史诗碎片那味了:

代码语言:javascript复制
BoxDecoration(
    color: Colors.transparent,
    borderRadius: BorderRadius.only(
      topLeft: Radius.circular(20),
      bottomRight: Radius.circular(20),
      bottomLeft: Radius.circular(5),
      topRight: Radius.circular(5),
    ),
    border: Border.all(color: Colors.red, width: 2),
    image: DecorationImage(
      image: AssetImage('assets/images/bg_6.jpeg'),
      fit: BoxFit.cover,
    ),
    boxShadow: [
      const BoxShadow(
          color: Colors.red,
          offset: Offset.zero,
          blurRadius: 2,
          spreadRadius: 2),
    ]
),

另外还有一个 ShapeDecoration 子类,顾名思义,它可以进行一些形状的处理。其中入参必须传入 ShapeBorder 类型的 shape 参数。关于 ShapeBorder ,详见 : 《Path在手,天下我有》

如下,通过一个 Flutter 自带的 CircleBorder 来测试一下:

代码语言:javascript复制
DecoratedBox(
  position: DecorationPosition.background,
  decoration: ShapeDecoration(
    shape: CircleBorder(),
    shadows: const [BoxShadow(
        color: Colors.red,
        offset: Offset.zero,
        blurRadius: 2,
        spreadRadius: 2)],
    image: DecorationImage(
      image: AssetImage('assets/images/bg_6.jpeg'),
      fit: BoxFit.cover,
    ),
  ),
  child: buildContent(),
);
3.自定义装饰

很多人问过我,如何加虚线边框。本质上就是在问如何通过绘制虚线,通过 DecoratedBox 装饰而已。在我发布的 dash_painter 包中有实现虚线装饰,就以此来讲述一下如何自定义装饰

代码语言:javascript复制
dependencies:
    ...
    dash_painter: ^1.0.2
代码语言:javascript复制
import 'package:dash_painter/dash_decoration.dart';

DecoratedBox(
  decoration: DashDecoration(
      pointWidth: 2,
      step: 5,
      pointCount: 1,
      radius: Radius.circular(15),
      gradient: SweepGradient(colors: [
        Colors.blue,
        Colors.red,
        Colors.yellow,
        Colors.green
      ])),
  child: buildContent(),
);

Widget buildContent() {
  return SizedBox(
    width: 70,
    height: 70,
    child: Icon(
      Icons.add, color: Colors.orangeAccent, size: 40),
  );
}

下面看一下 DashDecoration 的源码实现,首先定义可配置的参数,通过构造函数初始化。

DashDecoration 中必须实现抽象方法 createBoxPainter ,返回一个 BoxPainter 对象。

然后继承 BoxPainter ,将配置对象传进来,在 paint 里画就完事了。本身流程很简单,关键在于如何绘制。在 《Flutter 绘制指南 - 妙笔生花》 小册中系统地介绍了 Flutter 绘制相关的基础知识,感兴趣的可以看一看。

4. DecoratedBox 的源码实现

DecoratedBox 继承自 SingleChildRenderObjectWidget ,内部维护 RenderDecoratedBox 渲染对象来实现装饰功能。

核心代码是下面的 paint 方法,执行绘制。其中 super.paint(context, offset); 是绘制子组件,可见 background 是在绘制孩子前绘制,也就是作为背景,孩子在前面。而 foreground 会覆盖在孩子前面,也就是前景。画笔是通过 _decoration#createBoxPainter 创建的,也就是那个 BoxPainter 对象。

那本文到这里就结束了,谢谢观看,明天见~

0 人点赞