Flutter绘制-02-Canvas

3,050 阅读11分钟

查看目录-->

Flutter自定义控件分为三大类:

  • 组合控件,通过组合其他widget成为一个新的widget。
  • 自绘控件,通过使用canvas与paint来完全绘制。
  • 继承widget,使用RenderObject来绘制,但最终还是使用canvas来绘制。

本文重点

着重介绍自绘控件,因为所有的widget归根结底都是使用canvas和paint来绘制的,理解了二者,对于其他的widget原理有溯源的功效。

  • Canvas:画布
  • Paint:画笔 怎么做?
  • 继承CustomPainter
  • 重写paint方法与shouldRepaint方法
  • paint提供来canvas和size,canvas用于绘制,size用于确定大小
  • shouldRepaint用于确认是否每次都重新绘制

画什么

canvas.drawRect()画矩形;
void drawRect(Rect rect, Paint paint)

rect 矩形的描述

  • Rect.fromCenter({ Offset center, double width, double height }),根据中心点和宽高,定义一个矩形。
  • Rect.fromCircle({ Offset center, double radius }),根据中心点和半径定义一个矩形
  • Rect.fromLTRB(this.left, this.top, this.right, this.bottom),left左边框距离左边的距离,top上边框距离上边的距离,right右边框距离左边的距离,bottom下边框距离上边的距离。根据这四个值定义一个矩形。
  • Rect.fromLTWH(double left, double top, double width, double height),根据左上角顶点和宽高定义一个矩形。
  • Rect.fromPoints(Offset a, Offset b),根据左上角顶点和右下角顶点定义一个矩形。 示例: image.png
class _MyHomePageState extends State<MyHomePage> {
  bool flag = true;

  void change(bool value) {
    setState(() {
      flag = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: CustomPaint(
          size: Size(380, 560),
          painter: MyPainter(),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter{

  @override
  void paint(Canvas canvas, Size size) {
    test01(canvas, size);
  }

  void test00(Canvas canvas, Size size) {
    var paint = new Paint()
        ..color = Colors.orange[200]
        ..style = PaintingStyle.fill
        ..isAntiAlias = true;
    // 画矩形
    canvas.drawRect(Offset.zero & size, paint);
    paint
    ..color = Colors.green;
    canvas.drawRect(Rect.fromCenter(width: 200,height: 200,center: Offset(150, 150)), paint);

    paint
      ..color = Colors.blue;
    canvas.drawRect(Rect.fromCircle(radius: 50,center: Offset(150, 150)), paint);

    paint
      ..color = Colors.redAccent;
    canvas.drawRect(Rect.fromLTRB(10,10,200,100), paint);

    paint
      ..color = Colors.pink;
    canvas.drawRect(Rect.fromLTWH(10,250,100,100), paint);

    paint
      ..color = Colors.grey;
    canvas.drawRect(Rect.fromPoints(Offset(250, 250),Offset(350, 300)), paint);
  }


  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }

}
canvas.drawRRect()画圆角矩形

image.png

void test01(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形

    Rect rect = Rect.fromCircle(
        center: Offset(200, 200), radius: 150);
    RRect rRect = RRect.fromRectAndRadius(rect, Radius.circular(30));
    canvas.drawRRect(rRect, paint);
  }
canvas.drawDRRect()画环形圆角矩形

image.png

void test011(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形
    Rect rect1 = Rect.fromCircle(
        center: Offset(200, 200), radius: 140);
    Rect rect2 = Rect.fromCircle(
        center: Offset(200, 200), radius: 160);
    RRect rRect1 = RRect.fromRectAndRadius(rect1, Radius.circular(20));
    RRect rRect2 = RRect.fromRectAndRadius(rect2, Radius.circular(20));
    canvas.drawDRRect(rRect2, rRect1, paint);
  }
canvas.drawCircle()画圆
drawCircle(Offset c, double radius, Paint paint)
  • c 中心点
  • radius 圆半径
  • paint 画笔

示例: image.png

void test02(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形
    canvas.drawRect(Offset.zero & size, paint);

    paint ..color = Colors.blue[200];
    canvas.drawCircle(Offset(200, 200), 100, paint);
  }
canvas.drawOval()画椭圆

image.png

void test022(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形
    canvas.drawRect(Offset.zero & size, paint);

    paint..color = Colors.blue[200];
    canvas.drawOval(
        Rect.fromCenter(width: 200, height: 300, center: Offset(150, 250)),
        paint);
  }
canvas.drawArc()画弧型
void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
  • rect 弧所属椭圆的外接矩形,用于定位该弧的位置
  • startAngle,起始角度,按弧度制,顺时针
  • sweepAngle,画多少弧度,一个圆的弧度是 2PI,也就是2*3.14
  • useCenter,是否将弧与中心连接,形成一个扇形 image.png
void test08(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
//      ..style = PaintingStyle.fill
      ..style = PaintingStyle.stroke
      ..strokeWidth = 5
      ..isAntiAlias = true;
    Rect rect = Rect.fromCircle(
        center: Offset(200, 200), radius: 100);
    canvas.drawArc(rect, 0, 3.14, false, paint);
  }
canvas.drawPoints()画点

image.png 参数PointModel:

  • ui.PointMode.points,// 单独的点
  • ui.PointMode.polygon,// 所有的点按给定顺序连成线
  • ui.PointMode.lines,//画一条线,起始点为给定数组的前两个点
void test06(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形
    canvas.drawRect(Offset.zero & size, paint);
    paint
      ..style = PaintingStyle.stroke
      ..strokeWidth = 15
      ..strokeCap = StrokeCap.round
      ..color = Colors.black;
    canvas.drawPoints(
//        ui.PointMode.points,// 单独的点
//    ui.PointMode.polygon,// 所有的点按给定顺序连成线
    ui.PointMode.lines,//画一条线,起始点为给定数组的前两个点
        [Offset(100, 100), Offset(300, 100), Offset(200, 300)], paint);
  }
canvas.drawRawPoints() 画点

与drawPoints的区别在于,表示点的数据方式不一样。 参数PointModel:

  • ui.PointMode.points,// 单独的点
  • ui.PointMode.polygon,// 所有的点按给定顺序连成线
  • ui.PointMode.lines,//画一条线,起始点为给定数组的前两个点

PointMode.points

PointMode.polygon

PointMode.lines

void _drawRawPoints(Canvas canvas, Size size) {
    Float32List points = Float32List.fromList([
      -120, -20,-80, -80,-40,
      -40,0, -100,40, -140,
      80, -160,120, -100]);


    Paint paint = new Paint();
    paint ..color = Colors.redAccent[200]
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 20;

    canvas.drawRawPoints(PointMode.points, points, paint);
//    canvas.drawRawPoints(PointMode.lines, points, paint);
//    canvas.drawRawPoints(PointMode.polygon, points, paint);
  }
canvas.drawVertices() 画带属性的点

void _drawVertices(Canvas canvas, Size size) {
    Paint paint = new Paint();
    paint
      ..color = Colors.blue[200]
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 20;
    canvas.drawVertices(
        Vertices(VertexMode.triangleFan,
            [Offset(50, 50), Offset(50, -50), Offset(-50, -50)],
            colors: [Colors.redAccent, Colors.blueAccent, Colors.green],
//            indices: [0,0,0],
//            textureCoordinates: [Offset(-50, -50), Offset(50, 50), Offset(-50, 50)]
        ),
        BlendMode.srcIn,
        paint);
  }
canvas.drawLine()画线
void drawLine(Offset p1, Offset p2, Paint paint)
  • p1 线的起点
  • p2 线的终点

注意:

  • 画笔的style 更改为PaintingStyle.stroke
  • 可以调整线的粗细 strokeWidth = 3

示例: image.png

void test03(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形
    canvas.drawRect(Offset.zero & size, paint);

    paint
      ..color = Colors.black
      ..strokeWidth = 3
      ..style = PaintingStyle.stroke;
    canvas.drawLine(Offset(100, 150), Offset(250, 150), paint);

  }
canvas.drawPath()画路径

paint ..color = PaintingStyle.fill; image.png

void test07(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形
    Path path = Path();
    path.moveTo(100, 100);
    path.lineTo(100, 200);
    path.lineTo(200, 100);
    path.lineTo(200, 200);
    canvas.drawPath(path, paint);
  }

paint ..color = PaintingStyle.stroke; image.png

void test07(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
//      ..style = PaintingStyle.fill
      ..style = PaintingStyle.stroke
      ..strokeWidth = 5
      ..isAntiAlias = true;
    // 画矩形
    Path path = Path();
    path.moveTo(100, 100);
    path.lineTo(100, 200);
    path.lineTo(200, 100);
    path.lineTo(200, 200);
    canvas.drawPath(path, paint);
  }

path.close() image.png

void test07(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
//      ..style = PaintingStyle.fill
      ..style = PaintingStyle.stroke
      ..strokeWidth = 5
      ..isAntiAlias = true;
    // 画矩形
    Path path = Path();
    path.moveTo(100, 100);
    path.lineTo(100, 200);
    path.lineTo(200, 100);
    path.lineTo(200, 200);
    path.close();
    canvas.drawPath(path, paint);
  }
canvas.drawColor()画颜色
void drawColor(Color color, BlendMode blendMode)
  • blendMode 是颜色的混合模式 image.png
void test04(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 画矩形

    canvas.drawColor(Colors.blue[200], BlendMode.srcIn);
    canvas.drawRect(Offset.zero & size/2, paint);

  }
canvas.drawPaint() 用paint画画布

void _drawPaint1(Canvas canvas, Size size) {
    Path path = Path();
    path.lineTo(80, 80);
    path.lineTo(-80, 80);
    path.close();
    canvas.clipPath(path);
    canvas.drawPaint(new Paint()..color = Colors.blueAccent);
  }
canvas.drawShadow()画阴影
void drawShadow(Path path, Color color, double elevation, bool transparentOccluder)
  • path 阴影区域
  • color 阴影颜色
  • elevation 阴影高度,一般是向右下
  • transparentOccluder 如果阻塞对象不是不透明的,则阻塞“transparentoccluder”参数应为true.百度翻译的,没明白啥意思 image.png
void test09(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..strokeWidth = 5
      ..isAntiAlias = true;
    Path path = Path();
    path.moveTo(100, 100);
    path.lineTo(100, 200);
    path.lineTo(200, 100);
    path.lineTo(200, 200);
    canvas.drawPath(path, paint);
    canvas.drawShadow(path, Colors.orange, 10, true);
  }

画文字

textpainter.paint()
void _drawTextPaint(Canvas canvas) {
    var textpainter = TextPainter(
        text: TextSpan(
            text: '123456', style: TextStyle(fontSize: 40, color: Colors.red)),
        textAlign: TextAlign.center,
        textDirection: TextDirection.ltr);
    textpainter.layout();
    Size size = textpainter.size;
    textpainter.paint(canvas, Offset(-size.width / 2, -size.height / 2));
  }
canvas.drawParagraph()

void _drawTextWithParagraph(Canvas canvas) {
    TextAlign textAlign = TextAlign.center;
    var builder = ui.ParagraphBuilder(ui.ParagraphStyle(
      textAlign: textAlign,
      fontSize: 40,
      textDirection: TextDirection.ltr,
      maxLines: 1,
    ));
    var builder1 = ui.ParagraphBuilder(ui.ParagraphStyle(
        textAlign: TextAlign.right,
        fontSize: 40,
        textDirection: TextDirection.ltr,
        maxLines: 1));
    builder.pushStyle(
      ui.TextStyle(
          color: Colors.black87, textBaseline: ui.TextBaseline.alphabetic),
    );
    builder1.pushStyle(ui.TextStyle(
        color: Colors.red, textBaseline: ui.TextBaseline.alphabetic));

    builder.addText("Flutter Can");
    builder1.addText("ssssssss");
    ui.Paragraph paragraph = builder.build();
    ui.Paragraph paragraph1 = builder1.build();

    paragraph.layout(ui.ParagraphConstraints(width: 300));
    paragraph1.layout(ui.ParagraphConstraints(width: 400));

    canvas.drawParagraph(paragraph, Offset(-100, 0));
    canvas.drawParagraph(paragraph1, Offset(-200, -110));

    canvas.drawRect(Rect.fromLTRB(0, 0, 300, 40),
        _paint..color = Colors.blue.withAlpha(33));
  }

画图

在根目录建立images 存放图片资源,在pubspec.yaml中声明 assets 注意缩进,assets前是2个空格,- 前是2个空格,- 后是1个空格 图片加载

// 定义从assets加载图片的方法
Future<ui.Image> loadImageFromAssets(String path) async {
    ByteData data = await rootBundle.load(path);
    List<int> bytes =
        data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
    return decodeImageFromList(bytes);
  }
// 在初始时加载图片
@override
  void initState() {
    super.initState();
    _loadImage();
  }

  void _loadImage() async {
    _image = await loadImageFromAssets('images/a2.png');
    setState(() {});
  }
canvas.drawImage() 画图

void _drawImage(Canvas canvas) {
    if (image != null) {
      canvas.drawImage(
          image, Offset(-image.width / 2, -image.height / 2), _paint);
    }
  }
canvas.drawImageRect() 画部分图到指定区域

void drawImageRect(Image image, Rect src, Rect dst, Paint paint)

  • image,图片源
  • src,从图片上选取哪块区域
  • dst,画到什么区域
canvas.drawImageRect(
          image,
          Rect.fromCenter(
              center: Offset(image.width / 2, image.height / 2),
              width: 180,
              height: 180),
          Rect.fromLTRB(0, 0, 200, 200),
          _paint);
canvas.drawImageNine() 画.9图

void drawImageNine(Image image, Rect center, Rect dst, Paint paint)

  • image,源图片
  • cennter,设定拉伸区域
  • dst,画到什么位置

在填充dst时,如果宽度或高度不够,就以center为中心,划分成三行三列,中间行中间列是拉伸区域

canvas.drawImageNine(
          image,
          Rect.fromCenter(
              center: Offset(image.width / 2, image.height - 150.0),
              width: 1,
              height: 1.0),
          Rect.fromCenter(
              center: Offset(
                0,
                0,
              ),
              width: 430,
              height: 430),
          _paint);
canvas.drawAtlas()

从一个图上,截取指定区域rects的图片,并放到trasforms的区域内

void drawAtlas(Image atlas, List transforms, List rects, List? colors, BlendMode? blendMode, Rect? cullRect, Paint paint)

void _drawAtlas(Canvas canvas) {
    Paint paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;
    Rect cullRect = Rect.fromLTRB(50, 50, 50, 50);
    canvas.drawAtlas(
        image,
        [
          RSTransform.fromComponents(
              rotation: -10,
              scale: 1.0,
              anchorX: 0,
              anchorY: 0,
              translateX: 10,
              translateY: 10),
          RSTransform.fromComponents(
              rotation: 40,
              scale: 1.0,
              anchorX: 0,
              anchorY: 0,
              translateX: 90,
              translateY: 90)
        ],
        [Rect.fromLTWH(50, 50, 100, 100), Rect.fromLTWH(150, 150, 100, 100)],
        [Colors.redAccent, Colors.blueAccent],
        BlendMode.srcIn,
        cullRect,
        paint);
  }
canvas.drawRawAtlas() ???待处理

画布裁剪

裁剪后,canvas的所有操作都限定在裁剪区域内

canvas.clipPath() 按指定路径裁剪

 void _clipPath(Canvas canvas, Size size) {
    Path path = Path();
    path.lineTo(80, 80);
    path.lineTo(-80, 80);
    path.close();
    canvas.clipPath(path);
    canvas.drawPaint(new Paint()..color=Colors.redAccent);
  }
canvas.clipRect() 按矩形裁剪

注意clipOp参数:

  • ClipOp.intersect 裁剪画布 内

  • ClipOp.difference 裁剪画布 外

void _clipRect(Canvas canvas, Size size) {
    var rect = Rect.fromCenter(center: Offset.zero,width: 180,height: 120);
    canvas.clipRect(rect,doAntiAlias: true,clipOp: ui.ClipOp.intersect); // 裁剪画布  内
//    canvas.clipRect(rect,doAntiAlias: true,clipOp: ui.ClipOp.difference); // 裁剪画布  外
    canvas.drawPaint(new Paint()..color=Colors.redAccent);
  }
canvas.clipDRect() 按圆角矩形裁剪

  void _clipDRect(Canvas canvas, Size size) {
    var rect = Rect.fromCenter(center: Offset.zero,width: 180,height: 120);
    canvas.clipRRect(RRect.fromRectAndRadius(rect, Radius.circular(30)),doAntiAlias: true); //
    canvas.drawPaint(new Paint()..color=Colors.redAccent);
  }

画布的层

save(),saveLayer(),restore()
  • canvas.save(),保存之前画的内容与canvas的状态
  • canvas.saveLayer(rect,paint),保存之前画的内容,并新建一个图层,以后在此新图层上绘制。参数rect确定图层的范围,只能在此范围内绘制,超出范围的绘制不显示。参数paint表示其blendMode与之前的图层的混合模式。
  • canvas.restore(),将该方法与前面最近的一个save() 或saveLayer()之间的操作合并到一起,save与restore,saveLayer与restore是成对儿出现的,只有save没有restore,是会报错的。 image.png
void test10(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    canvas.drawPaint(paint);// 整个区域
    paint ..color = Colors.blue[200];
    canvas.drawRect(Offset.zero&size, paint);// 绘制区域
    paint ..color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(200,200),radius:100), paint);
    // 保存之前的绘制内容
    canvas.save();
    // 接着绘制一个矩形,是在前面的图层上继续绘制的
    paint.color = Colors.grey;
    canvas.drawRect(Rect.fromCircle(center:Offset(250,300),radius:100), paint);
    // 保存
    canvas.restore();
    // 设定混合模式
    paint.blendMode = BlendMode.src;
    //保存之前并新建一个图层,并指定新图层的区域与混合模式
    canvas.saveLayer(Rect.fromCircle(center:Offset(270,350),radius:100), paint);
    paint ..color = Colors.orange;
    //在新的图层上画一个矩形,设定矩形范围超过图层范围
    canvas.drawRect(Rect.fromCircle(center:Offset(270,350),radius:150), paint);
    // 保存
    canvas.restore();
  }

可见,在新的图层上画一个超出图层范围的矩形,超出范围的内容没有显示,只有图层区域内的显示了出来

canvas.getSaveCount() 获取save栈中的层数

每save()或saveLayer()一次 getSaveCount() 取值 +1;

每restore()一次,getSaveCount() 取值 -1;

如:

    print("canvas1="+canvas.getSaveCount().toString());// canvas1=1
    canvas.save();
    canvas.save();
    print("canvas2="+canvas.getSaveCount().toString());// canvas2= 3
    canvas.restore();
    print("canvas3="+canvas.getSaveCount().toString());// canvas3= 2
    canvas.restore();
    print("canvas4="+canvas.getSaveCount().toString());// canvas4= 1

画布变换

canvas.translate()平移

canvas.translate(dx,dy) 指的是整个canvas向xy分别平移dx dy的距离 image.png

// 平移
  void test11(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 初始位置
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制区域
    paint ..color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存之前的绘制内容
    canvas.save();
    canvas.translate(200, 200);//向xy200平移
    paint.color = Colors.red[200];
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制canvas区域
    paint.color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存
    canvas.restore();

  }

平移后,canvas绘制的内容显示在平移后的位置。

canvas.scale(sx,sy)缩放

canvas.scale(0.5,2):x轴缩小为一半,y轴放大为2倍 看效果: image.png

// 缩放
  void test12(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 初始位置
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制区域
    paint ..color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存之前的绘制内容
    canvas.save();
    canvas.scale(0.5,0.5);// 缩小为原来的一半
    paint.color = Colors.red[200];
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制canvas区域
    paint.color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存
    canvas.restore();
  }
canvas.rotate(value)旋转
  • value: 取值pi=3.14,顺时针旋转180读,取值pi *2 顺时针旋转360度。
  • 旋转的圆心是canvas的左顶点,即(0,0) 看效果: 先平移,再旋转: image.png
// 旋转
  void test13(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 初始位置
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制区域
    paint ..color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存之前的绘制内容
    canvas.save();
    canvas.translate(200, 200);//向xy200平移
    canvas.rotate(1);// 旋转1弧度
    paint.color = Colors.red[200];
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制canvas区域
    paint.color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存
    canvas.restore();
  }
canvas.skew(sx,sy)斜切

取值为tan(sx) tan(sy) image.png

 // 斜切
  void test14(Canvas canvas, Size size) {
    var paint = new Paint()
      ..color = Colors.orange[200]
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    // 初始位置
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制区域
    paint ..color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存之前的绘制内容
    canvas.save();
    canvas.skew(pi/4, 0);//
//    canvas.skew(tan(45), 0);//
    paint.color = Colors.red[200];
    canvas.drawRect(Offset.zero&size/2, paint);// 绘制canvas区域
    paint.color = Colors.green[200];
    canvas.drawRect(Rect.fromCircle(center:Offset(100,100),radius:50), paint);// 画一个矩形
    // 保存
    canvas.restore();
  }
canvas.transform() 矩阵变换

上面四种画布变换,最终都都是基于transform的。

void _transform(Canvas canvas, Size size) {
    Path path = Path();
    path.lineTo(60, 60);
    path.lineTo(-60, 60);
    path.lineTo(60, -60);
    path.lineTo(-60, -160);
    path.close();
    canvas.drawPath(path, _paint);
//    canvas.translate(140, 0);
    canvas.transform(Float64List.fromList([
      1, 0, 0, 0,
      0, 1, 0, 0,
      0, 0, 1, 0,
      120, 0, 0, 1]));
    canvas.drawPath(
        path,
        _paint
          ..style = PaintingStyle.stroke
          ..strokeWidth = 2);
  }