【问题标题】:Efficient Canvas rendering in FlutterFlutter 中的高效 Canvas 渲染
【发布时间】:2020-10-06 06:46:41
【问题描述】:

我一直在尝试开发一个绘图应用程序,但所有示例代码(包括 The Boring Flutter Development Show 中的示例代码)都不能很好地转化为实际使用。

主要问题是CustomPaint 的绘制操作过于昂贵,并且每一个点、每一帧都重新绘制。随着点数的增加,颤振应用每帧的渲染时间显着增加

从我花时间寻找解决这个问题的方法开始,我发现了这些

  1. RepaintBoundary:栅格化图层

  2. 使用SingleChildRenderObjectWidget 和RenderProxyBox 的自定义小部件:必须实现paint 方法并且无法传递控制器

我认为上述任何解决方案都不能很好地满足我的需求:无需重新绘制即可顺利进行画布绘制操作。我什至尝试简化要点,但由于CustomPaint 的固有机制,这也不起作用

如果有办法将画布作为小部件传递并附加控制器,则可以轻松存储捕获的点并更有效地使用基本的画布操作,如 canvas.drawPath() 或 canvas.drawLine()

任何建议都会有所帮助。谢谢!

【问题讨论】:

  • PictureRecorder 也许?
  • @pskink 从我见过的所有示例中,我找不到任何将 PictureRecorder 或 Canvas 作为小部件传递的示例,您可以在其中呈现实时触摸事件。如果我最近开始学习 Flutter,如果我听起来很幼稚,我深表歉意。
  • @Dhruva 你找到解决办法了吗?
  • @Alex 我会发布答案

标签: flutter dart rxdart flutter-canvas


【解决方案1】:

这是控制器类

class DrawingController extends ChangeNotifier {

  List<Offset> _points = []
   
  .... // Perform operations on data points
  ....

  void add(Offset point) {
    _points.add(point);
    notifyListeners();
  }

}

这是CustomPaint 类

class Painter extends CustomPainter {
  DrawingController controller;

  Painter(this.controller) : super(repaint: controller); //This is important

  @override
  void paint(Canvas canvas, Size size) {
     //Paint function
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

在手势检测器中,只需调用 controller.add(point) 即可在抓取新点时添加它们

我不确定这是最有效的绘画方式,但它在 60hz 屏幕上将绘画时间减少到 13 毫秒,在 120Hz 屏幕上减少到 9 毫秒。一个明显的缺点是,当笔划有很多点时,单个笔划(onTapdownEvent 到 onDragEndEvent)的渲染速度非常慢(最多 18 毫秒)。一旦你开始一个新的中风,这个问题就会消失。我尝试在几个论坛上询问,这是我在挖掘颤振源代码后能想到的最好的。

我在 snapdragon 855 设备上分析了此功能,因此处理器不是瓶颈。如果有人找到更好的解决方案,请发布。

【讨论】:

    【解决方案2】:

    一个有用的提示是添加 Timer.run(setState())。这样,它只会在可能的时候更新。而不是加载 update1 update2 update3...等。它加载 update1 然后如果它可以加载 update2 但如果 update1 花了很长时间它转到 update3。一般来说,它只是看起来更流畅,但不一定会加快速度。示例:

    scaleStart(ScaleStartDetails d) => startPoint = d.focalPoint - _offset;
    
    scaleUpdate(ScaleUpdateDetails d) {
      _offset = d.focalPoint - startPoint;
      scale = min(max(1, scale * (d.scale + 13) / 14), 128);
      Timer.run(() => setState(() {}));
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 1970-01-01
      • 1970-01-01
      • 2019-12-28
      • 1970-01-01
      相关资源
      最近更新 更多