Jav*_*d98 7 profiling custom-painting flutter flutter-animation
我需要一个加载小部件,将移动的正弦和余弦函数绘制到画布中。我使用 CustomPaint 小部件和 CustomPainter 对其进行编码,没有任何问题,但是当我分析它时,我发现它的运行速度约为 49 fps,而不是 60 fps。UI 线程运行良好,每帧大约需要 6 毫秒,但光栅线程需要更长的时间。我尝试在画布上绘制更少的点(在 for 循环中使用 i=i+5 而不是 i++),但结果完全相同。
\n\xc2\xbf有人可以建议我如何提高性能吗?下面是小部件代码,以及 Raster 线程在每一帧中执行的操作的 DevTools 屏幕截图,以防它有用。
\nimport \'dart:math\';\n\nimport \'package:flutter/material.dart\';\n\nclass LoadingChart extends StatefulWidget{\n final Color color1;\n final Color color2;\n final double lineWidth;\n final bool line;\n final Size size;\n\n const LoadingChart({\n @required this.color1,\n @required this.color2,\n @required this.size,\n @required this.lineWidth,\n this.line = true,\n Key key\n }): super(key: key);\n\n @override\n State<StatefulWidget> createState() => _LoadingChartState();\n\n}\n\nclass _LoadingChartState extends State<LoadingChart>\n with SingleTickerProviderStateMixin{\n AnimationController _controller;\n\n\n double randomHeight(Random random, double max){\n return random.nextDouble()*max;\n }\n\n @override\n void initState() {\n _controller = AnimationController(vsync: this, duration: Duration(seconds: 1));\n _controller.addListener(() {setState(() {});});\n _controller.repeat();\n\n super.initState();\n }\n\n @override\n void dispose(){\n _controller.dispose();\n super.dispose();\n }\n\n @override\n Widget build(BuildContext context) {\n return SizedBox(\n height: widget.size.height,\n width: widget.size.width,\n child: CustomPaint(\n painter: PathPainter(\n color1: widget.color1,\n color2: widget.color2,\n value: _controller.value,\n line: widget.line,\n ),\n )\n );\n }\n\n}\n\nclass PathPainter extends CustomPainter {\n final Color color1;\n final Color color2;\n final double lineWidth;\n final bool line;\n\n final double value;\n\n PathPainter({\n @required this.value,\n this.color1=Colors.red,\n this.color2=Colors.green,\n this.line = true,\n this.lineWidth=4.0,\n }): super();\n\n @override\n void paint(Canvas canvas, Size size) {\n final height = size.height;\n final width = size.width;\n\n Paint paint1 = Paint()\n ..color = color1\n ..style = PaintingStyle.stroke\n ..strokeWidth = lineWidth;\n\n Paint paint2 = Paint()\n ..color = color2\n ..style = PaintingStyle.stroke\n ..strokeWidth = lineWidth;\n\n Path path1 = Path();\n Path path2 = Path();\n\n /* If line is true, draw sin and cos functions, otherwise, just some points */\n for (double i = 0; i < width; i=i+5){\n double f = i*2*pi/width + 2*pi*value;\n double g = i*2*pi/width - 2*pi*value;\n if (i == 0){\n path1.moveTo(0, height/2 + height/6*sin(f));\n path2.moveTo(0, height/2 + height/6*cos(g));\n continue;\n }\n\n path1.lineTo(i, height/2 + height/6*sin(f));\n path2.lineTo(i, height/2 + height/6*cos(g));\n }\n\n /* Draw both lines */\n canvas.drawPath(path1, paint1);\n canvas.drawPath(path2, paint2);\n }\n\n @override\n bool shouldRepaint(PathPainter oldDelegate) {\n return oldDelegate.value != value || oldDelegate.color1 != color1\n || oldDelegate.color2 != color2 || oldDelegate.line != line\n || oldDelegate.lineWidth != lineWidth;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\nPS:我正在配置文件模式下运行应用程序,因此这应该不是问题。我还想提一下,它是屏幕上唯一被重绘的小部件。\n非常感谢!
\nCustomPainter 可以接收可听的,因此也许您可以使用那里的动画控制器在每次勾选时更新它
class _LoadingChartState extends State<LoadingChart>
with SingleTickerProviderStateMixin{
AnimationController _controller;
double randomHeight(Random random, double max){
return random.nextDouble()*max;
}
@override
void initState() {
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
//_controller.addListener(() {setState(() {});}); no need to setState
_controller.repeat();
super.initState();
}
@override
void dispose(){
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: widget.size.height,
width: widget.size.width,
child: CustomPaint(
willChange: true, //this can help (Whether the raster cache should be told that this painting is likely)
painter: PathPainter(
color1: widget.color1,
color2: widget.color2,
line: widget.line,
listenable: _controller //pass the controller as it is (An animationController extends a Listenable)
),
)
);
}
}
Run Code Online (Sandbox Code Playgroud)
在 PathPainter 中,您向构造函数提供可监听对象,并将其传递给接受名为 repaint 的可监听对象的 CustomPainter 构造函数
class PathPainter extends CustomPainter {
final Animation listenable;
final Color color1;
final Color color2;
final double lineWidth;
final bool line;
PathPainter({
this.listenable,
this.color1=Colors.red,
this.color2=Colors.green,
this.line = true,
this.lineWidth=4.0,
}): super(repaint: listenable); //don't forget calling the CustomPainter constructor with super
@override
void paint(Canvas canvas, Size size) {
double value = listenable.value; // get its value here
final height = size.height;
final width = size.width;
Paint paint1 = Paint()
..color = color1
..style = PaintingStyle.stroke
..strokeWidth = lineWidth;
Paint paint2 = Paint()
..color = color2
..style = PaintingStyle.stroke
..strokeWidth = lineWidth;
Path path1 = Path();
Path path2 = Path();
/* If line is true, draw sin and cos functions, otherwise, just some points */
for (double i = 0; i < width; i=i+5){
double f = i*2*pi/width + 2*pi*value;
double g = i*2*pi/width - 2*pi*value;
if (i == 0){
path1.moveTo(0, height/2 + height/6*sin(f));
path2.moveTo(0, height/2 + height/6*cos(g));
continue;
}
path1.lineTo(i, height/2 + height/6*sin(f));
path2.lineTo(i, height/2 + height/6*cos(g));
}
/* Draw both lines */
canvas.drawPath(path1, paint1);
canvas.drawPath(path2, paint2);
}
@override
bool shouldRepaint(PathPainter oldDelegate) {
//delete the oldDelegate.value, it doesn't exists anymore
return oldDelegate.color1 != color1
|| oldDelegate.color2 != color2 || oldDelegate.line != line
|| oldDelegate.lineWidth != lineWidth;
}
}
Run Code Online (Sandbox Code Playgroud)
我处于调试模式,因此我希望您在配置文件模式下获得更好的性能
| 归档时间: |
|
| 查看次数: |
4653 次 |
| 最近记录: |