如何确保我的CustomPaint小部件绘画存储在栅格缓存中?
问题描述:
我有一个显示该点处的黑点,其中用户触摸屏幕像这样的应用程序:如何确保我的CustomPaint小部件绘画存储在栅格缓存中?
黑点可以由用户移动他/她拖动他的手指上屏幕。
背景是一个昂贵的绘画操作,所以我在堆栈中创建了两个单独的小部件,希望背景小部件绘画将存储在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;
}
答
它颤动的特异性。我们没有反应,只有当他们的状态/道具改变时才会重新绘制“组件”。
在扑,每一个时代都有小部件重新绘制整个树也会这样做的。
通常,这不是一个问题,而且相当快。但是有些情况下(比如你的情况),你不需要。这是一个相当无证的小部件,但重要的是出现! 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,
),
),
+0
这很有用 - 谢谢!还要感谢关于重新绘制边界部分的书签上的视频链接:) – Mark
顺便说一句,你为什么用'Listener'为DRAP /下降?为此,有一个'Draggable'小部件。 – Darky
感谢您的提示 - 我没有意识到Draggable,但它并不适合我的情况:我实际上为我的协作白板webapp写了一个Flutter应用程序:https://whiteboardfox.com/ – Mark