1.认识 DecoratedBox 组件
DecoratedBox
组件可能单独使用的频率不是很高,因为它被集成在了 Container
组件中,但装饰的使用方式是共通的,源码中说 DecoratedBox
会在其孩子的前景或背景上绘制 Decoration
装饰对象。这说明 Decoration
才是装饰的重点,我们需要了解或自定义 Decoration
。
下面是 DecoratedBox
组件类的定义
和 构造方法
,可以看出它继承自 SingleChildRenderObjectWidget
。构造时必须传入尺寸 decoration
参数,可以传入 position
入参。
decoration
成员的类型是 Decoration
,表示装饰对象。position
成员的类型是 DecorationPosition
枚举,表示在前景绘制还是在背景绘制。
final Decoration decoration;
final DecorationPosition position;
enum DecorationPosition {
background,
foreground,
}
2.认识 Decoration 及其子类
首先需要注意的是: Decoration
是一个抽象类,无法直接实例化使用。
Flutter
框架中提供了四个实现类,其中 BoxDecoration
是我们最常用的。
比如下面通过 BoxDecoration
的 borderRadius
可以指定装饰的圆角,通过 color
指定填充的颜色。
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
来测试一下:
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 包中有实现虚线装饰,就以此来讲述一下如何自定义装饰
。
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
对象。
那本文到这里就结束了,谢谢观看,明天见~