前言:
Flutter是一个UI框架,一切皆Widget,Flutter可以说和Android是无缝对接,毕竟都是出自Google,Material风格更是轻车熟路,对Android同学来说,上手较快.本文要讲的Canvas也和Android中Canvas也是极其相似,一脉相承.Canvas一般可以用来绘制比较难以实现的特殊图形,控件等,比如一些多边形,弧形等等吧.Canvas就是画布,内部封装了用于绘制绘制基本图形的接口,比如矩形,圆形,点,线等.
Flutter中为我们提供了封装好的组件CustomPaint Widget,这个组件与画笔Paint Widget组合使用就可以绘制出需要的图形.
Flutter绘制的基本步骤:
1. 创建继承于基类的绘制类
///
/// @ClassName FlutterPainter
/// @Description 绘制类
/// @Author waitwalker
/// @Date 2020-03-07
///
class FlutterPainter extends CustomPainter {
}
2. 在绘制类中重写paint()和shouldRepaint()方法
///
/// @ClassName FlutterPainter
/// @Description 绘制类
/// @Author waitwalker
/// @Date 2020-03-07
///
class FlutterPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return null;
}
}
3. 初始化画笔Paint&调用Canvas绘制图形
///
/// @ClassName FlutterPainter
/// @Description 绘制类
/// @Author waitwalker
/// @Date 2020-03-07
///
class FlutterPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
/// 初始化画笔
var paint = Paint()
..strokeWidth = 25.0
..color = Colors.red;
/// 通过canvas画一条直线
/// 这里可以根据需要绘制圆形,矩形等等
canvas.drawLine(Offset(95, 0), Offset(95, 300), paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
4. 初始化CustomPaint添加成员变量绘制类,并把CustomPaint添加到Widget树中
class _HomeState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CustomPaint(
foregroundPainter: FlutterPainter(),
child: Container(
width: 200,
height: 200,
color: Color(0x5a00C800),
),
),
),
);
}
///
/// @ClassName FlutterPainter
/// @Description 绘制类
/// @Author waitwalker
/// @Date 2020-03-07
///
class FlutterPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return null;
}
}
}
CustomPainter 说明:
CustomPainter是真实绘制的基础类,需要绘制的图形和画笔都是在此类中实现,一般会自定义一个类继承此基类,然后重写两个方法如下:
1.1 paint 方法
这个方法就是实现具体绘制的方法
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
}
1.2 shouldRepaint 方法
这个方法控制的是是否需要重绘
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return null;
}
CustomPaint 绘制组件
CustomPaint可以理解为绘制的封装类,其内部成员变量就包含CustomPainter,其构造函数:
const CustomPaint({
Key key,
this.painter,
this.foregroundPainter,
this.size = Size.zero,
this.isComplex = false,
this.willChange = false,
Widget child,
})
1.painter: 自定义绘制的基础类绘制效果会显示在child的下面,效果如上:
2.foregroundPainter:自定义绘制的基础类绘制效果会显示在child的上面,效果如上:
3.child:子控件,也就是上图中的绿色区域.
4.size:绘制区域大小,其取决于child.
(1)如果child == null,则绘制区域为size大小;
(2)如果child != null,则绘制区域为child大小;
(3)如果想child != null && 指定size大小,可以用SizeBox包裹一下CustomPaint;
5.isComplex:是否复杂绘制,默认false,如果true,则会开启缓存,避免一些不必要的绘制提高性能.
6.willChange:这个和isComplex一起使用,默认false,如果isComplex == true,willChange表示绘制下一帧是否会改变
Canvas 的方法
Canvas 的操作主要有两类:
- 针对 Canvas 的变换操作,如平移、旋转、缩放、图层等
- 绘制基础图形的操作,如线段、路径、图片、几何图形等
绘制相关操作:
- drawArc(Rect rect,double startAngle, double sweepAngle, bool useCenter, Paint paint)在给定的矩形中画一个弧线。它从椭圆周围的
startAngle
弧度开始,直至椭圆周围的startAngle
+sweepAngle
弧度,零弧度是椭圆右侧与矩形中心相交的水平线相交的点,正角绕椭圆顺时针走。如果useCenter
为真,弧线就会闭合回到中心,形成一个圆扇形。否则,弧线不闭合,形成一个圆段。
参数 | 类型 | 说明 |
---|---|---|
rect | Rect | 圆弧所在椭圆的外接矩形 |
startAngle | double | 起始位置的弧度。弧度制 |
sweepAngle | double | 设置圆弧扫过多少弧度。弧度制 |
useCenter | bool | 表示是否链接到圆弧所在椭圆的中心 |
paint | Paint | 画笔 |
- drawAtlas
(
Image atlas, List<
RSTransform>
transforms, List<
Rect>
rects, List<
Color>
colors, BlendMode blendMode, Rect cullRect, Paint paint)
在画布上绘制部分图像。当你只想在画布上绘制图像的一部分时(例如使用精灵或缩放时),此方法可以进行优化。 比直接使用剪辑或遮罩更有效。 - drawCircle(Offset c, double radius, Paint paint)绘制一个以第一个参数给出的点为中心的圆,其半径由第二个参数给出,第三个参数给出Paint。圆圈是被填充还是被描边(或者两者都有)由Paint.style控制。
- drawColor(Color color, BlendMode blendMode)将给定的Color应用给定的BlendMode绘制到画布上,给定的颜色为源色,背景为目标色。
- drawDRRect(RRect outer, RRect inner, Paint paint)用给定的Paint绘制一个由两个圆角矩形的差值组成的形状。这个形状是填充还是描边(或者两者都有)由Paint.style控制。
- drawImage(Image image, Offset p, Paint paint)将给定的Image以给定的Offset的左上角绘制到画布中。使用给定的Paint将图像合成到画布中。
- drawImageNine(Image image, Rect center, Rect dst, Paint paint)使用给定的 Paint 将给定的 Image 绘制到画布上。使用给定的Paint将给定的Image绘制到画布中。通过绘制两条水平线和两条垂直线将图像分割成九个部分进行绘制,其中中心参数描述了由这四条线相交的四个点形成的矩形。这样就形成了一个3×3的区域网格,中心区域由中心参数描述)。角落中的四个区域是在
dst
描述的目标矩形的四个角上绘制的,没有缩放。剩下的五个区域是通过拉伸来绘制的,使它们完全覆盖目标矩形,同时保持它们的相对位置。 - drawImageRect(Image image, Rect src, Rect dst, Paint paint)在
dst
参数给定的轴对齐的矩形中,将src
参数描述的给定图像的一部分绘制到画布中。 - drawLine(Offset p1, Offset p2, Paint paint)使用给定的
paint
在给定的两点之间绘制一条线。 描边该行,此调用将忽略Paint.style的值。 - drawOval(Rect rect, Paint paint)绘制一个轴对齐的椭圆形,用给定的Paint填充给定的轴对齐的矩形。椭圆是被填充还是被描边(或两者都有)由Paint.style控制。
- drawPaint(Paint paint)用给定的Paint填充画布。
- drawParagraph(Paragraph paragraph, Offset offset)将给定Paragraph中的文本在给定Offset处绘制到这个画布中。
- drawPath(Path path, Paint paint)用给定的 Paint 绘制给定的 Path。这个形状是被填充还是被描边(或者两者都有)由 Paint.style 控制。如果路径被填充,那么它的子路径将被隐式关闭(参见 Path.close)。
- drawPicture(Picture picture)在画布上绘制给定的图片。要创建图片,请参阅PictureRecorder。
- drawPoints(PointMode pointMode, List points, Paint paint)根据给定的PointMode绘制一个点的序列。
- drawRawAtlas(Image atlas, Float32List rstTransforms, Float32List rects, Int32List colors, BlendMode blendMode, Rect cullRect, Paint paint)将图像的一部分
atlas
画在画布上。 - drawRawPoints(PointMode pointMode, Float32List points, Paint paint)根据给定的PointMode绘制一个点的序列。
- drawRect(Rect rect, Paint paint)用给定的Paint绘制一个矩形。矩形是被填充还是被描边(或两者都有)由Paint.style控制。
- drawRRect(RRect rrect, Paint paint)用给定的Paint绘制一个圆角矩形。矩形是被填充还是被描边(或两者都有)由Paint.style控制。
- drawShadow(Path path, Color color, double elevation, bool transparentOccluder)为Path画出代表给定material标高的阴影。
- drawVertices(Vertices vertices, BlendMode blendMode, Paint paint)将Vertices的集合绘制到画布上。
变换相关操作:
- scale(double sx, [double sy])在当前变换中添加一个轴对齐的标尺,在水平方向上按第一个参数缩放,在垂直方向上按第二个参数缩放。
- skew(double sx, double sy)在当前变换中增加一个轴对齐的倾斜度,第一个参数是以原点为单位顺时针上升的水平倾斜度,第二个参数是以原点为单位顺时针上升的垂直倾斜度。
- transform(Float64List matrix4)将当前变换乘以指定的4×4变换矩阵,该矩阵指定为以列为主的值列表。
- translate(double dx, double dy)在当前的变换中添加一个平移,通过第一个参数水平移动坐标空间,通过第二个参数垂直移动坐标空间。
- rotate(double radians)在当前的变换中加入旋转。参数的单位是顺时针的弧度。
- getSaveCount()返回保存栈中的条目数,包括初始状态。这意味着如果画布是干净的,则返回1,每次调用
save
和saveLayer
都会使其递增,每次匹配调用restore
都会使其递减。 - restore()弹出当前的保存堆栈(如果有要弹出的内容)。 否则,什么都不做。
- save()在保存堆栈上保存当前变换和剪辑的副本。
- saveLayer(Rect bounds, Paint paint)在保存堆栈上保存当前变换和剪辑的副本,然后创建一个新的组,后续调用将成为该组的一部分。当随后打开保存堆栈时,该组将被扁平化为一个图层,并应用给定的
paint
的Paint.colorFilter和Paint.blendMode。
裁剪相关操作:
- clipPath(Path path, {bool doAntiAlias: true})将剪辑区域缩小至目前剪辑与给定路径的交点。如果
doAntiAlias
为true,则剪辑将被消除锯齿。 - clipRect(Rect rect, {ClipOp clipOp: ClipOp.intersect, bool doAntiAlias: true})缩小剪辑区域至目前剪辑与指定矩形的交点
- clipRRect(RRect rrect, {bool doAntiAlias: true})将剪辑区域缩小到当前剪辑和给定圆角矩形的交点。
Paint 画笔
在Canvas上绘图时要使用的样式的描述。大多数Canvas上的API都会取一个Paint对象来描述该操作要使用的样式。简单说,该类主要是用来设置真正画笔的一些属性。【 Paint是画笔,画笔有多个属性,可以设置颜色,线宽,填充等样式.】
属性 | 类型 | 简述 |
---|---|---|
isAntiAlias | bool | 是否开启抗锯齿,开启抗锯齿能够使边缘平滑 |
color | Color | 描边或填充形状时使用的颜色。 |
colorFilter | ColorFilter | 绘制形状或合成图层时应用的颜色滤镜。 |
filterQuality | FilterQuality | 控制应用滤镜(如 maskFilter )或绘制图像(如 Canvas.drawImageRect 或 Canvas.drawImageNine )时的性能与质量权衡。 |
invertColors | bool | 绘制时图像的颜色是否反转 |
maskFilter | MaskFilter | 遮罩滤镜(例如,模糊),在形状被绘制后,但在它被合成到图像之前,应用于它。 |
imageFilter | ImageFilter | 绘制光栅图像时要使用的ImageFilter 。例如,如果要使用Canvas.drawImage 模糊图像,应用ImageFilter.blur |
shader | Shader | 描边或填充形状时要使用的着色器。 |
strokeCap | StrokeCap | 当样式设置为PaintingStyle.stroke 时,要放置在线条末端的边缘风格。如圆角、方形等 |
strokeJoin | StrokeJoin | 设置两个绘制形状衔接处的风格。如圆角、方形等 |
strokeWidth | double | 当样式设置为PaintingStyle.stroke 时,画笔的宽度。宽度以逻辑像素为单位 |
style | PaintingStyle | 填充方式。PaintingStyle.fill 充满;PaintingStyle.stroke 空心 |
blendMode | BlendMode | 像素混合模式。当画一个shape或者合成图层的时候会生效。 |
关于BlendMode
类型,官方做了详细解释,这里给一篇 中文翻译链接