如何确保我的CustomPaint小部件绘画存储在栅格缓存中? [英] How to ensure my CustomPaint widget painting is stored in the raster cache?
问题描述
我有一个应用程序,它在用户触摸屏幕的位置显示一个黑点,如下所示:
I have an app that displays a black dot at the point where the user touches the screen like this:
用户在屏幕上拖动手指时可以移动黑点.
The black dot can be moved by the user as he/she drags his finger on the screen.
背景是一个昂贵的绘制操作,因此我在堆栈中创建了两个单独的小部件,希望将背景小部件绘制存储在Flutter栅格缓存中.但这并没有存储-每次黑点移动时,Flutter都会调用我昂贵的绘画方法.
The background is an expensive paint operation, so I have created two separate widgets in a stack, hoping that the background widget painting will be stored in the Flutter raster cache. But it's not stored - Flutter calls my expensive paint method every time the black dot moves.
我在做什么错了?
这是我的代码:
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;
}
推荐答案
这是Flutter的特殊性.我们不在React中,这里的组件"仅在状态/道具更改时才重新粉刷.
It's a specificity of Flutter. We are not in React, where "Components" are repainted only when their state/props change.
在Flutter中,每次小部件必须重新绘制整棵树时,也会重新绘制.
In Flutter, every time a widget has to repaint the whole tree will too.
通常,这不是问题,而且速度很快.但是在某些情况下(例如您的情况),您不希望如此.这是一个未公开但很重要的窗口小部件出现的地方! RepaintBoundary
Usually, this is not a problem and fairly fast. But in some cases (such as yours), you don't want that. And this is where a fairly undocumented but important widget appears! RepaintBoundary
关于Flutter渲染管道的工作原理,这里有一个精彩的演讲: https://www .youtube.com/watch?v = UUfXWzp0-DU
There's an excellent talk about how Flutter's rendering pipeline works, here: https://www.youtube.com/watch?v=UUfXWzp0-DU
但是简而言之,考虑RepaintBoundary
是什么,它告诉Flutter将绘画操作分为不同的部分.
But in short, consider RepaintBoundary
as what tells Flutter to split the painting operation into different parts.
无论如何,解决方案?
将Expensive
小部件包装在RepaintBoundary
中.突然间,您获得了60 FPS.
Anyway, the solution ?
Wrap your Expensive
widget in a RepaintBoundary
. And suddenly you get 60 FPS.
new RepaintBoundary(
child: new CustomPaint(
painter: new ExpensivePainter(),
isComplex: true,
willChange: false,
),
),
这篇关于如何确保我的CustomPaint小部件绘画存储在栅格缓存中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!