Flutter Canvas如何高效绘制大量不同颜色的Raw Points
快速绘制大量带自定义颜色的点
直接使用drawRawPoints无法为单个点指定不同颜色,因为它仅接受单一Paint对象。逐个绘制点性能太差,这里推荐两种高效方案:
方案一:按颜色分组批量绘制
把相同颜色的点归类到同一组,对每组颜色调用一次drawRawPoints。这样绘制次数等于颜色种类数,远小于总点数,能大幅提升性能。
修改后的代码示例:
void _paintPoints(Canvas canvas, List matrix, Size size) { final width = size.width / matrix.length; final height = size.height / matrix.first.length; // 用Map按颜色分组存储点坐标 final Map<Color, List<double>> colorToPoints = {}; for (var i = 0; i < matrix.length; i++) { for (var j = 0; j < matrix[i].length; j++) { final x = i * width; final y = j * height; final color = Color.fromARGB( matrix[i][j][3], matrix[i][j][0], matrix[i][j][1], matrix[i][j][2], ); // 将点添加到对应颜色的分组中 colorToPoints.putIfAbsent(color, () => []); colorToPoints[color]!.add(x); colorToPoints[color]!.add(y); } } // 遍历每个颜色分组,批量绘制点 colorToPoints.forEach((color, points) { final floatPoints = Float32List.fromList(points); canvas.drawRawPoints( PointMode.points, floatPoints, Paint() ..color = color ..blendMode = BlendMode.srcOver ..strokeWidth = 2.0, ); }); }
方案二:使用Image一次性绘制
如果颜色种类极多,分组效果有限,可以先将所有点绘制到一个Image对象中,再把整个Image画到Canvas上。这种方式只需要一次Canvas绘制操作,性能最优,但需要处理图像的创建与销毁:
Future<Image> _createPointsImage(List matrix, Size size) async { final width = size.width / matrix.length; final height = size.height / matrix.first.length; final recorder = PictureRecorder(); final canvas = Canvas(recorder); // 按颜色分组绘制到PictureRecorder final colorToPoints = <Color, List<double>>{}; for (var i = 0; i < matrix.length; i++) { for (var j = 0; j < matrix[i].length; j++) { final x = i * width; final y = j * height; final color = Color.fromARGB( matrix[i][j][3], matrix[i][j][0], matrix[i][j][1], matrix[i][j][2], ); colorToPoints.putIfAbsent(color, () => []); colorToPoints[color]!.add(x); colorToPoints[color]!.add(y); } } colorToPoints.forEach((color, points) { canvas.drawRawPoints( PointMode.points, Float32List.fromList(points), Paint() ..color = color ..strokeWidth = 2.0, ); }); final picture = recorder.endRecording(); return picture.toImage(size.width.floor(), size.height.floor()); } // 在Widget中使用示例: late Image pointsImage; @override void initState() { super.initState(); _createPointsImage(yourMatrix, yourSize).then((image) { setState(() => pointsImage = image); }); } @override void dispose() { pointsImage.dispose(); super.dispose(); } void _paintPoints(Canvas canvas, Size size) { if (pointsImage != null) { canvas.drawImage(pointsImage, Offset.zero, Paint()); } }
注意:方案二适合点数据不频繁更新的场景,如果点需要实时刷新,方案一的性能表现更均衡。
内容的提问来源于stack exchange,提问作者MaLa
相关产品推荐
相关产品推荐

