如何确保我的CustomPaint小部件绘画存储在栅格缓存中?

问题描述:

我有一个显示该点处的黑点,其中用户触摸屏幕像这样的应用程序:如何确保我的CustomPaint小部件绘画存储在栅格缓存中?

enter image description here

黑点可以由用户移动他/她拖动他的手指上屏幕。

背景是一个昂贵的绘画操作,所以我在堆栈中创建了两个单独的小部件,希望背景小部件绘画将存储在Flutter栅格缓存中。但它不存储 - 每次黑点移动时,Flutter都会调用我昂贵的绘画方法。

我在做什么错?

这里是我的代码:

import 'package:flutter/material.dart'; 
import 'dart:math'; 

void main() { 
    runApp(new MyApp()); 
} 

class MyApp extends StatelessWidget { 
    @override 
    Widget build(BuildContext context) { 
    return new MaterialApp(
     home: new MyHomePage(), 
    ); 
    } 
} 

class MyHomePage extends StatefulWidget { 
    @override 
    State createState() => new MyHomePageState(); 
} 

class MyHomePageState extends State<MyHomePage> { 
    GlobalKey _paintKey = new GlobalKey(); 
    Offset _offset; 

    @override 
    Widget build(BuildContext context) { 
    return new Scaffold(
     body: new Stack(
     fit: StackFit.expand, 
     children: <Widget>[ 
      new CustomPaint(
      painter: new ExpensivePainter(), 
      isComplex: true, 
      willChange: false, 
     ), 
      new Listener(
      onPointerDown: _updateOffset, 
      onPointerMove: _updateOffset, 
      child: new CustomPaint(
       key: _paintKey, 
       painter: new MyCustomPainter(_offset), 
       child: new ConstrainedBox(
       constraints: new BoxConstraints.expand(), 
      ), 
      ), 
     ) 
     ], 
    ), 
    ); 
    } 

    _updateOffset(PointerEvent event) { 
    RenderBox referenceBox = _paintKey.currentContext.findRenderObject(); 
    Offset offset = referenceBox.globalToLocal(event.position); 
    setState(() { 
     _offset = offset; 
    }); 
    } 
} 

class ExpensivePainter extends CustomPainter { 
    @override 
    void paint(Canvas canvas, Size size) { 
    print("Doing expensive paint job"); 
    Random rand = new Random(12345); 
    List<Color> colors = [ 
     Colors.red, 
     Colors.blue, 
     Colors.yellow, 
     Colors.green, 
     Colors.white, 
    ]; 
    for (int i = 0; i < 5000; i++) { 
     canvas.drawCircle(
      new Offset(
       rand.nextDouble() * size.width, rand.nextDouble() * size.height), 
      10 + rand.nextDouble() * 20, 
      new Paint() 
      ..color = colors[rand.nextInt(colors.length)].withOpacity(0.2)); 
    } 
    } 

    @override 
    bool shouldRepaint(ExpensivePainter other) => false; 
} 

class MyCustomPainter extends CustomPainter { 
    final Offset _offset; 

    MyCustomPainter(this._offset); 

    @override 
    void paint(Canvas canvas, Size size) { 
    if (_offset == null) return; 
    canvas.drawCircle(_offset, 10.0, new Paint()..color = Colors.black); 
    } 

    @override 
    bool shouldRepaint(MyCustomPainter other) => other._offset != _offset; 
} 
+0

顺便说一句,你为什么用'Listener'为DRAP /下降?为此,有一个'Draggable'小部件。 – Darky

+0

感谢您的提示 - 我没有意识到Draggable,但它并不适合我的情况:我实际上为我的协作白板webapp写了一个Flutter应用程序:https://whiteboardfox.com/ – Mark

它颤动的特异性。我们没有反应,只有当他们的状态/道具改变时才会重新绘制“组件”。

在扑,每一个时代都有小部件重新绘制整个树也会这样做的。

通常,这不是一个问题,而且相当快。但是有些情况下(比如你的情况),你不需要。这是一个相当无证的小部件,但重要的是出现! RepaintBoundary

有一个很好的谈扑动的渲染管线是如何在这里工作:https://www.youtube.com/watch?v=UUfXWzp0-DU

但在短期,考虑RepaintBoundary因为什么告诉扑喷涂操作分成不同的部分。

无论如何,解决方案? 将您的Expensive小部件包装在RepaintBoundary中。突然你会得到60 FPS。

 new RepaintBoundary(
     child: new CustomPaint(
      painter: new ExpensivePainter(), 
      isComplex: true, 
      willChange: false, 
     ), 
    ), 

enter image description here

+0

这很有用 - 谢谢!还要感谢关于重新绘制边界部分的书签上的视频链接:) – Mark