【问题标题】:Flutter draw SVG in CustomPaint (Canvas)Flutter 在 CustomPaint (Canvas) 中绘制 SVG
【发布时间】:2020-01-12 10:08:35
【问题描述】:

我有这样的事情:

CustomPaint(
       painter: CurvePainter(),
)

在这堂课上我正在画画:

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import './myState.dart';
import './models/mode.dart';
final String rawSvg = '''<svg viewBox="...">...</svg>''';

class CurvePainter extends CustomPainter {
  MyState _myState;
  DrawableRoot svgRoot;
  CurvePainter(MyState myState) {
    this._myState = myState;
    this.loadAsset();
  }

  void loadAsset() async {
    this.svgRoot = await svg.fromSvgString(rawSvg, rawSvg);// The canvas that is your board.
  }

  @override
  void paint (Canvas canvas, Size size) {
    canvas.translate(_myState.translateX, _myState.translateY);
    if(this.svgRoot != null){
        svgRoot.scaleCanvasToViewBox(canvas, size);
        svgRoot.clipCanvasToViewBox(canvas);
        // svgRoot.draw(canvas, size);
    }
}

有人知道如何在paint方法中绘制SVG吗? 我找到了这个库 https://pub.dev/packages/flutter_svg#-readme-tab- 。 使用我的代码出现错误:未处理的异常:状态不佳:viewBox 元素必须为 4 个元素长

如果我可以缩放和旋转画布内的 svg,我会很好。但这是可选的。

【问题讨论】:

    标签: svg flutter dart paint


    【解决方案1】:

    来自README

    import 'package:flutter_svg/flutter_svg.dart';
    final String rawSvg = '''<svg viewBox="...">...</svg>''';
    final DrawableRoot svgRoot = await svg.fromSvgString(rawSvg, rawSvg);
    
    // If you only want the final Picture output, just use
    final Picture picture = svgRoot.toPicture();
    
    // Otherwise, if you want to draw it to a canvas:
    // Optional, but probably normally desirable: scale the canvas dimensions to
    // the SVG's viewbox
    svgRoot.scaleCanvasToViewBox(canvas);
    
    // Optional, but probably normally desireable: ensure the SVG isn't rendered
    // outside of the viewbox bounds
    svgRoot.clipCanvasToViewBox(canvas);
    svgRoot.draw(canvas, size);
    

    你可以适应的:

    class CurvePainter extends CustomPainter {
      CurvePainter(this.svg);
    
      final DrawableRoot svg;
      @override
      void paint(Canvas canvas, Size size) {
           canvas.drawLine(...);
           svg.scaleCanvasToViewBox(canvas);
           svg.clipCanvasToViewBox(canvas);
           svg.draw(canvas, size);
      }
    }
    

    我建议在您的应用中尽早找到一些方法来获取异步部分,可能使用 FutureBuilder 或 ValueListenableBuilder。

    披露:我是 Flutter SVG 的作者/主要维护者。

    【讨论】:

    • 谢谢。我收到此错误:未处理的异常:错误状态:viewBox 元素必须是 4 个元素长
    • 你的viewBox格式必须是"1 2 3 4",里面有四个数字。
    • 嘿@DanField 我正在使用自定义滑块,我想在 customPainter 中使用 SVG 图标我有点困惑你能检查一下问题吗。我添加了以下链接:stackoverflow.com/questions/62001542/…
    • 0.22.0 版本上不能这样工作。方法参数不再匹配。现在,scaleCanvasToViewBox 需要 sizedraw 需要 Rect
    • 如果有人需要它,您可以在0.22.0 版本上编写它。请丹,如果我错了,请纠正我:·)dart svg.scaleCanvasToViewBox(canvas, size); svg.clipCanvasToViewBox(canvas); svg.draw(canvas, Rect.fromLTWH(0, 0, size.width, size.height));
    【解决方案2】:

    最终我发现直接在 Canvas 中绘制 SVG 很麻烦。相反,我使用 path_drawing 将 SVG 路径和转换复制到 Dart 代码,并将它们呈现为 Paths 和 Canvas.drawPath。这具有甚至根本不是资产的优势; SVG 数据此时实际上是代码。您可以轻松转换回 SVG。这个过程有点像这样:

    1. 在您从import 'package:path_drawing/path_drawing.dart'; 渲染的文件中,将path_drawing: 0.4.1 添加到pubspec.yamlflutter pub get
    2. 使用 parseSvgPathData 方法从 SVG 中复制粘贴所有路径作为路径常量。 (路径字符串类似于M 86.102000,447.45700 L 86.102000,442.75300 .....
      • 如果 SVG 中有多个路径,您可以组合多个路径:
        • static final Path complexPathToDraw = parseSvgPathData("path_1").addPath(parseSvgPathData("path_2"));
    3. 通常 SVG 会包含在一些翻译中 (&lt;g transform='translate()&gt;)。而drawPath 只能从左上角渲染路径。所以你必须翻译到合适的位置。渲染时,在绘制之前平移画布(1)首先纠正 SVG 中的平移,(2)在旁边缩放到您想要的大小,(3)在 Canvas 上转到您真正想要的位置。然后绘制,并将 Canvas 恢复到未转换的状态。但请记住,这些矩阵是按逆序添加到我们如何在逻辑上分解它的,因为线性代数很愚蠢。
      • canvas.save();
        canvas.translate(dxToRenderPosition, dyToRenderPosition);
        canvas.scale(sxFromSvgSizeToDesiredRenderSize);
        canvas.translate(dxFromSvg, dyFromSvg);
        canvas.drawPath(complexPathToDraw, Paint());
        canvas.restore();
        
      
      

    【讨论】:

      【解决方案3】:

      我遇到了与此类似的问题,我想在 canvas 的一小部分上绘制一个按比例缩小的 Svg。

      为了让它工作,我不得不使用这个代码:

      Size desiredSize = Size(60, 40);
      // get the svg from a preloaded array of DrawableRoot corresponding to all the Svg I might use
      final DrawableRoot svgRoot = drawables[i];
      canvas.save();
      // [center] below is the Offset of the center of the area where I want the Svg to be drawn
      canvas.translate(center.dx - desiredSize.width / 2, center.dy - desiredSize.height / 2);
      Size svgSize = svgRoot.viewport.size;
      var matrix = Matrix4.identity();
      matrix.scale(desiredSize.width / svgSize.width, desiredSize.height / svgSize.height);
      canvas.transform(matrix.storage);
      svgRoot.draw(canvas, Rect.zero); // the second argument is not used in DrawableRoot.draw() method
      canvas.restore();
      

      这样,您可以在画布上渲染复杂的 Svg 并继续对其进行一些工作。

      例如:您可以在同一个画布上绘制多个 Svg 并在它们上面绘制。

      【讨论】:

        猜你喜欢
        • 2020-02-23
        • 2020-09-03
        • 1970-01-01
        • 2018-12-02
        • 2022-10-19
        • 2012-03-16
        • 2023-03-19
        • 1970-01-01
        • 2014-08-23
        相关资源
        最近更新 更多