Flutter开发进阶之Canvas

Flutter开发进阶之Canvas

在Flutter开发中Canvas作为一个绘制2D图形的工具,提供了一系列绘图方法,可以用来绘制各种形状、线条、文本和图像等;

Canvas对象是作为CustomPainter的子组件进行构建的;

dart 复制代码
void paint(Canvas canvas, Size size);

一、绘制的保存和恢复

Canvas通过使用以下方法调用原生层(C++)的绘图操作;

dart 复制代码
factory Canvas(PictureRecorder recorder, [ Rect? cullRect ]) = _NativeCanvas;

通过以下方法保存上下文和恢复;

dart 复制代码
void save();
void saveLayer(Rect? bounds, Paint paint);

void restore();
void restoreToCount(int count);
/// 保存数量
int getSaveCount();

二、绘制的变换

添加平移变换,分别在x轴和轴上;

dart 复制代码
void translate(double dx, double dy);

添加对应轴的缩放变换,若不指定sy则x轴和y轴都等比例缩放sx;

dart 复制代码
void scale(double sx, [double? sy]);

根据radians的弧度进行旋转变换;

dart 复制代码
void rotate(double radians);

相对原始角度对应的百分比倾斜变换;

dart 复制代码
void skew(double sx, double sy);

变换4x4矩阵;

dart 复制代码
void transform(Float64List matrix4);

变换的获取;

dart 复制代码
Float64List getTransform();

三、绘制的渲染流水线

还可以按指定规则进行裁剪;

dart 复制代码
void clipRect(Rect rect, { ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true });
void clipRRect(RRect rrect, {bool doAntiAlias = true});
void clipPath(Path path, {bool doAntiAlias = true});

/// 获取裁剪的边界
Rect getLocalClipBounds();
Rect getDestinationClipBounds();

通过以下API进行形状图元的组合、着色;

dart 复制代码
/// 着色
void drawColor(Color color, BlendMode blendMode);
/// 通过画笔进行点对点划线
void drawLine(Offset p1, Offset p2, Paint paint);
/// 画笔填充
void drawPaint(Paint paint);
/// 绘制矩形
void drawRect(Rect rect, Paint paint);
/// 绘制圆角矩形
void drawRRect(RRect rrect, Paint paint);
/// 绘制两个圆角矩形之差,填充或描边由画笔决定
void drawDRRect(RRect outer, RRect inner, Paint paint);
/// 绘制椭圆
void drawOval(Rect rect, Paint paint);
/// 绘制圆
void drawCircle(Offset c, double radius, Paint paint);
/// 绘制圆弧
void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint);
/// 根据path绘制,一般是组合图形
void drawPath(Path path, Paint paint);
/// 给定位置绘制图片
void drawImage(Image image, Offset offset, Paint paint);
void drawImageRect(Image image, Rect src, Rect dst, Paint paint);
/// 图像分割成3x3绘制
void drawImageNine(Image image, Rect center, Rect dst, Paint paint);
/// 绘制图片
void drawPicture(Picture picture);
/// 给定位置的文本绘制
void drawParagraph(Paragraph paragraph, Offset offset);
/// 绘制点序列
void drawPoints(PointMode pointMode, List<Offset> points, Paint paint);
void drawRawPoints(PointMode pointMode, Float32List points, Paint paint);
/// 绘制顶点
void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint);
/// 对绘制图像多个部分进行优化,可以对局部进行控制
void drawAtlas(Image atlas,
                 List<RSTransform> transforms,
                 List<Rect> rects,
                 List<Color>? colors,
                 BlendMode? blendMode,
                 Rect? cullRect,
                 Paint paint);
void drawRawAtlas(Image atlas,
                    Float32List rstTransforms,
                    Float32List rects,
                    Int32List? colors,
                    BlendMode? blendMode,
                    Rect? cullRect,
                    Paint paint);
/// 绘制阴影
void drawShadow(Path path, Color color, double elevation, bool transparentOccluder);

四、绘制的路径

Canvas使用Path来描述描述2D图形路径,路径可以是线段、二次贝塞尔曲线、三次贝塞尔曲线等,这些都可以组合在一起形成一个复杂的图形;

Path可以通过以下的方法来调用原生层的操作;

dart 复制代码
factory Path() = _NativePath;

factory Path.from(Path source) {
    final _NativePath clonedPath = _NativePath._();
    (source as _NativePath)._clone(clonedPath);
    return clonedPath;
  }

通过以下方法决定如何计算路径内部;

dart 复制代码
PathFillType get fillType;
set fillType(PathFillType value);

以下从点开始的路径;

dart 复制代码
/// 点的移动从开始到重新开始
void moveTo(double x, double y);
void relativeMoveTo(double dx, double dy);

/// 直线的连线到重新连线
void lineTo(double x, double y);
void relativeLineTo(double dx, double dy);

/// 贝塞尔曲线
void quadraticBezierTo(double x1, double y1, double x2, double y2);
void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2);

/// 三次贝塞尔
void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3);
void relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3);

/// 贝塞尔线段
void conicTo(double x1, double y1, double x2, double y2, double w);
void relativeConicTo(double x1, double y1, double x2, double y2, double w);

/// 直线或圆弧
void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo);
void arcToPoint(Offset arcEnd, {
    Radius radius = Radius.zero,
    double rotation = 0.0,
    bool largeArc = false,
    bool clockwise = true,
  });
void relativeArcToPoint(
    Offset arcEndDelta, {
    Radius radius = Radius.zero,
    double rotation = 0.0,
    bool largeArc = false,
    bool clockwise = true,
  });

以下直接给定图形的路径;

dart 复制代码
/// 矩形
void addRect(Rect rect);
/// 椭圆
void addOval(Rect oval);
/// 圆弧
void addArc(Rect oval, double startAngle, double sweepAngle);
/// 线段
void addPolygon(List<Offset> points, bool close);
/// 圆角
void addRRect(RRect rrect);

以下是路径的组合运算;

dart 复制代码
/// 添加路径
void addPath(Path path, Offset offset, {Float64List? matrix4});
/// 添加子路径
void extendWithPath(Path path, Offset offset, {Float64List? matrix4});
/// 关闭路径
void close();
/// 复位
void reset();
/// 点是否在路径内
bool contains(Offset point);
/// 路径的副本
Path shift(Offset offset);
Path transform(Float64List matrix4);
/// 路径的边界
Rect getBounds();

/// 对路径进行组合
static Path combine(PathOperation operation, Path path1, Path path2) {
    final _NativePath path = _NativePath();
    if (path._op(path1 as _NativePath, path2 as _NativePath, operation.index)) {
      return path;
    }
    throw StateError('Path.combine() failed.  This may be due an invalid path; in particular, check for NaN values.');
  }
/// 多部分的路径轮廓属性,一个Path通常有0到多个轮廓线组成
PathMetrics computeMetrics({bool forceClosed = false});

五、绘制的画笔

Canvas使用Paint描述如何绘制图形,例如颜色、样式、混合模式等,以上我称之为画笔;
isAntiAlias :抗锯齿;
color :填充的颜色;
blendMode :图形混合时合成的模式;
style :是否绘制形状的内部,形状的边缘,或两者;
strokeWidth :线的宽度;
strokeCap :在绘制的线的末端放置的结束类型;
strokeJoin :连接点的类型;
strokeMiterLimit :斜接长度限制;
maskFilter :蒙版滤镜;
filterQuality :控制采样位图时使用的性能和质量权衡;
shader :形状着色器;
colorFilter :颜色滤镜;
imageFilter :图像滤镜;
invertColors:颜色反转。

以上时Flutter中Canvas绘图部分,具体的应用在实际开发中可能是地图线路绘制、AI图像转换、动画绘制等,如需深入还需了解计算机的渲染机制

相关推荐
花王江不语2 小时前
android studio 配置硬件加速 haxm
android·ide·android studio
江太翁4 小时前
mediapipe流水线分析 三
android·mediapipe
与火星的孩子对话5 小时前
Unity进阶课程【六】Android、ios、Pad 终端设备打包局域网IP调试、USB调试、性能检测、控制台打印日志等、C#
android·unity·ios·c#·ip
tmacfrank6 小时前
Android 网络全栈攻略(四)—— TCPIP 协议族与 HTTPS 协议
android·网络·https
fundroid7 小时前
Kotlin 协程:Channel 与 Flow 深度对比及 Channel 使用指南
android·kotlin·协程
草字7 小时前
cocos 打包安卓
android
DeBuggggggg8 小时前
centos 7.6安装mysql8
android
浩浩测试一下9 小时前
渗透信息收集- Web应用漏洞与指纹信息收集以及情报收集
android·前端·安全·web安全·网络安全·安全架构
移动开发者1号10 小时前
深入理解原子类与CAS无锁编程:原理、实战与优化
android·kotlin
陈卓41010 小时前
MySQL-主从复制&分库分表
android·mysql·adb