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图像转换、动画绘制等,如需深入还需了解计算机的渲染机制

相关推荐
一头小火烧1 小时前
flutter打包签名问题
flutter
sunly_1 小时前
Flutter:异步多线程结合
flutter
AiFlutter1 小时前
Flutter网络通信-封装Dio
flutter
B.-1 小时前
Flutter 应用在真机上调试的流程
android·flutter·ios·xcode·android-studio
有趣的杰克2 小时前
Flutter【04】高性能表单架构设计
android·flutter·dart
大耳猫7 小时前
主动测量View的宽高
android·ui
帅次9 小时前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
枯骨成佛10 小时前
Android中Crash Debug技巧
android
iFlyCai11 小时前
Xcode 16 pod init失败的解决方案
ios·xcode·swift
sunly_13 小时前
Flutter:父组件,向子组件传值,子组件向二级页面传值
flutter