/** * 渲染优化方案 - 实现代码 * * 优化策略: * 1. CustomPainter 性能调优 * 2. 分层渲染(静态/动态分离) * 3. GPU 加速利用 * * @version 1.0.0 * @date 2026-03-07 * @author 性能优化专家 */ import 'package:flutter/material.dart'; import 'dart:ui' as ui; import '../domain/models/core_models.dart'; import '../domain/managers/selection_manager.dart'; // ============================================================================ // 1. CustomPainter 性能调优 // ============================================================================ /// 渲染层类型 enum RenderLayerType { staticLayer, // 静态层(网格、背景) semiStatic, // 半静态层(元件,不常变化) dynamicLayer, // 动态层(拖拽、连线、选择框) } /// 渲染层配置 class RenderLayerConfig { final RenderLayerType type; final bool shouldCache; final Duration cacheExpiry; final int maxCacheSize; const RenderLayerConfig({ required this.type, this.shouldCache = true, this.cacheExpiry = const Duration(seconds: 5), this.maxCacheSize = 3, }); factory RenderLayerConfig.static() => const RenderLayerConfig( type: RenderLayerType.staticLayer, shouldCache: true, ); factory RenderLayerConfig.semiStatic() => const RenderLayerConfig( type: RenderLayerType.semiStatic, shouldCache: true, cacheExpiry: Duration(seconds: 2), ); factory RenderLayerConfig.dynamic() => const RenderLayerConfig( type: RenderLayerType.dynamicLayer, shouldCache: false, ); } /// 优化的 CustomPainter 基类 abstract class OptimizedCustomPainter extends CustomPainter { bool _isCached = false; ui.Picture? _cachedPicture; Size? _cachedSize; DateTime? _cachedAt; final RenderLayerConfig _config; OptimizedCustomPainter({RenderLayerConfig? config}) : _config = config ?? const RenderLayerConfig.dynamic(); @override void paint(Canvas canvas, Size size) { if (_config.shouldCache && _isCached && _cachedPicture != null) { // 检查缓存是否过期 if (_cachedAt != null && DateTime.now().difference(_cachedAt!) > _config.cacheExpiry) { _invalidateCache(); } // 检查尺寸是否变化 else if (_cachedSize == size) { canvas.drawPicture(_cachedPicture!); return; } } // 录制绘制命令 final recorder = ui.PictureRecorder(); final recordingCanvas = Canvas(recorder); paintContent(recordingCanvas, size); if (_config.shouldCache) { _cachedPicture = recorder.endRecording(); _cachedSize = size; _cachedAt = DateTime.now(); _isCached = true; } // 绘制到实际画布 if (_cachedPicture != null) { canvas.drawPicture(_cachedPicture!); } } /// 子类实现绘制内容 void paintContent(Canvas canvas, Size size); /// 使缓存失效 void _invalidateCache() { _cachedPicture?.dispose(); _cachedPicture = null; _isCached = false; _cachedSize = null; _cachedAt = null; } /// 公开的重绘方法 void markNeedsRepaint() { _invalidateCache(); notifyListeners(); } @override bool shouldRepaint(covariant OptimizedCustomPainter oldDelegate) { // 默认实现:总是重绘 return true; } @override void dispose() { _cachedPicture?.dispose(); _cachedPicture = null; super.dispose(); } } // ============================================================================ // 2. 分层渲染(静态/动态分离) // ============================================================================ /// 分层渲染器 class LayeredRenderer extends StatefulWidget { final Design design; final double zoomLevel; final Offset offset; final SelectionManager selectionManager; final WiringState? wiringState; final Rect? selectionRect; final Component? hoveredComponent; final PinReference? hoveredPin; const LayeredRenderer({ super.key, required this.design, required this.zoomLevel, required this.offset, required this.selectionManager, this.wiringState, this.selectionRect, this.hoveredComponent, this.hoveredPin, }); @override State createState() => _LayeredRendererState(); } class _LayeredRendererState extends State { // 静态层控制器 late StaticLayerPainter _staticLayer; // 半静态层控制器 late SemiStaticLayerPainter _semiStaticLayer; // 动态层控制器 late DynamicLayerPainter _dynamicLayer; @override void initState() { super.initState(); _staticLayer = StaticLayerPainter(); _semiStaticLayer = SemiStaticLayerPainter(); _dynamicLayer = DynamicLayerPainter(); // 添加监听器 _staticLayer.addListener(_onLayerChanged); _semiStaticLayer.addListener(_onLayerChanged); _dynamicLayer.addListener(_onLayerChanged); } @override void didUpdateWidget(LayeredRenderer oldWidget) { super.didUpdateWidget(oldWidget); // 检查哪些层需要更新 bool staticChanged = false; bool semiStaticChanged = false; bool dynamicChanged = false; // 网格、背景等静态元素通常不变 // 这里可以检查是否需要更新 // 元件变化 → 半静态层 if (widget.design.components != oldWidget.design.components || widget.design.nets != oldWidget.design.nets) { semiStaticChanged = true; } // 交互状态变化 → 动态层 if (widget.wiringState != oldWidget.wiringState || widget.selectionRect != oldWidget.selectionRect || widget.hoveredComponent != oldWidget.hoveredComponent || widget.hoveredPin != oldWidget.hoveredPin || widget.selectionManager.selectedObjects != oldWidget.selectionManager.selectedObjects) { dynamicChanged = true; } // 更新各层数据 if (semiStaticChanged) { _semiStaticLayer.updateData( design: widget.design, zoomLevel: widget.zoomLevel, offset: widget.offset, ); } if (dynamicChanged) { _dynamicLayer.updateData( selectionManager: widget.selectionManager, wiringState: widget.wiringState, selectionRect: widget.selectionRect, hoveredComponent: widget.hoveredComponent, hoveredPin: widget.hoveredPin, ); } // 标记需要重绘的层 if (semiStaticChanged) _semiStaticLayer.markNeedsRepaint(); if (dynamicChanged) _dynamicLayer.markNeedsRepaint(); } void _onLayerChanged() { setState(() { // 触发重建 }); } @override Widget build(BuildContext context) { return Stack( children: [ // 静态层(最底层) CustomPaint( painter: _staticLayer, size: Size.infinite, ), // 半静态层(中间层) CustomPaint( painter: _semiStaticLayer, size: Size.infinite, ), // 动态层(最上层) CustomPaint( painter: _dynamicLayer, size: Size.infinite, ), ], ); } @override void dispose() { _staticLayer.removeListener(_onLayerChanged); _semiStaticLayer.removeListener(_onLayerChanged); _dynamicLayer.removeListener(_onLayerChanged); _staticLayer.dispose(); _semiStaticLayer.dispose(); _dynamicLayer.dispose(); super.dispose(); } } // ============================================================================ // 2.1 静态层绘制器(网格、背景) // ============================================================================ class StaticLayerPainter extends OptimizedCustomPainter { double zoomLevel = 1.0; Offset offset = Offset.zero; static const double gridSize = 20.0; StaticLayerPainter() : super(config: const RenderLayerConfig.static()); void updateData({required double zoom, required Offset offset}) { zoomLevel = zoom; this.offset = offset; } @override void paintContent(Canvas canvas, Size size) { _drawBackground(canvas, size); _drawGrid(canvas, size); } void _drawBackground(Canvas canvas, Size size) { final paint = Paint()..color = const Color(0xFFFAFAFA); canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint); } void _drawGrid(Canvas canvas, Size size) { final paint = Paint() ..color = const Color(0xFFE0E0E0) ..strokeWidth = 0.5; final startX = (-offset.dx / zoomLevel); final startY = (-offset.dy / zoomLevel); final endX = startX + size.width / zoomLevel; final endY = startY + size.height / zoomLevel; // 批量绘制垂直线 final verticalPoints = []; for (double x = (startX / gridSize).floor() * gridSize; x < endX; x += gridSize) { verticalPoints.add(Offset(x, startY)); verticalPoints.add(Offset(x, endY)); } if (verticalPoints.isNotEmpty) { canvas.drawLines( ui.PointsMode.pairs, verticalPoints, paint, ); } // 批量绘制水平线 final horizontalPoints = []; for (double y = (startY / gridSize).floor() * gridSize; y < endY; y += gridSize) { horizontalPoints.add(Offset(startX, y)); horizontalPoints.add(Offset(endX, y)); } if (horizontalPoints.isNotEmpty) { canvas.drawLines( ui.PointsMode.pairs, horizontalPoints, paint, ); } } @override bool shouldRepaint(covariant StaticLayerPainter oldDelegate) { return oldDelegate.zoomLevel != zoomLevel || oldDelegate.offset != offset; } } // ============================================================================ // 2.2 半静态层绘制器(元件、网络) // ============================================================================ class SemiStaticLayerPainter extends OptimizedCustomPainter { Design? design; double zoomLevel = 1.0; Offset offset = Offset.zero; // 预计算的绘制数据 final List<_PrecomputedComponent> _precomputedComponents = []; final List<_PrecomputedNet> _precomputedNets = []; SemiStaticLayerPainter() : super(config: const RenderLayerConfig.semiStatic()); void updateData({ required Design design, required double zoomLevel, required Offset offset, }) { this.design = design; this.zoomLevel = zoomLevel; this.offset = offset; // 预计算元件数据 _precomputeComponents(); _precomputeNets(); } void _precomputeComponents() { _precomputedComponents.clear(); if (design == null) return; for (final component in design!.components.values) { _precomputedComponents.add(_PrecomputedComponent( id: component.id, position: Offset( component.position.x.toDouble(), component.position.y.toDouble(), ), rotation: component.rotation, name: component.name, pins: component.pins .map((pin) => Offset( (component.position.x + pin.x).toDouble(), (component.position.y + pin.y).toDouble(), )) .toList(), )); } } void _precomputeNets() { _precomputedNets.clear(); if (design == null) return; for (final net in design!.nets.values) { if (net.connections.length < 2) continue; final points = []; for (final conn in net.connections) { if (conn.position != null) { points.add(Offset( conn.position!.x.toDouble(), conn.position!.y.toDouble(), )); } } if (points.length >= 2) { _precomputedNets.add(_PrecomputedNet( id: net.id, points: points, )); } } } @override void paintContent(Canvas canvas, Size size) { // 应用变换 canvas.save(); canvas.translate(offset.dx, offset.dy); canvas.scale(zoomLevel); // 绘制网络 _drawNets(canvas); // 绘制元件 _drawComponents(canvas); canvas.restore(); } void _drawComponents(Canvas canvas) { final bodyPaint = Paint() ..color = const Color(0xFF333333) ..style = PaintingStyle.stroke ..strokeWidth = 2.0; final fillPaint = Paint() ..color = const Color(0xFFFFFFFF).withOpacity(0.1) ..style = PaintingStyle.fill; const size = 40.0; for (final comp in _precomputedComponents) { // 绘制元件主体 final rect = Rect.fromLTWH( comp.position.dx - size / 2, comp.position.dy - size / 2, size, size, ); canvas.drawRect(rect, fillPaint); canvas.drawRect(rect, bodyPaint); // 绘制引脚 final pinPaint = Paint() ..color = const Color(0xFF333333) ..style = PaintingStyle.fill; for (final pinPos in comp.pins) { canvas.drawCircle(pinPos, 4.0, pinPaint); } } } void _drawNets(Canvas canvas) { final paint = Paint() ..color = const Color(0xFF4CAF50) ..strokeWidth = 2.0 ..style = PaintingStyle.stroke; for (final net in _precomputedNets) { for (int i = 0; i < net.points.length - 1; i++) { canvas.drawLine(net.points[i], net.points[i + 1], paint); } } } @override bool shouldRepaint(covariant SemiStaticLayerPainter oldDelegate) { return oldDelegate.design != design || oldDelegate.zoomLevel != zoomLevel || oldDelegate.offset != offset; } } // ============================================================================ // 2.3 动态层绘制器(交互元素) // ============================================================================ class DynamicLayerPainter extends OptimizedCustomPainter { SelectionManager? selectionManager; WiringState? wiringState; Rect? selectionRect; Component? hoveredComponent; PinReference? hoveredPin; DynamicLayerPainter() : super(config: const RenderLayerConfig.dynamic()); void updateData({ required SelectionManager selectionManager, required WiringState? wiringState, required Rect? selectionRect, required Component? hoveredComponent, required PinReference? hoveredPin, }) { this.selectionManager = selectionManager; this.wiringState = wiringState; this.selectionRect = selectionRect; this.hoveredComponent = hoveredComponent; this.hoveredPin = hoveredPin; } @override void paintContent(Canvas canvas, Size size) { // 绘制悬停高亮 if (hoveredComponent != null) { _drawHoverHighlight(canvas, hoveredComponent!); } // 绘制选中框 if (selectionRect != null) { _drawSelectionRect(canvas); } // 绘制连线 if (wiringState != null) { _drawWiringLine(canvas); } } void _drawHoverHighlight(Canvas canvas, Component component) { final paint = Paint() ..color = const Color(0xFF64B5F6) ..style = PaintingStyle.stroke ..strokeWidth = 3.0; const size = 40.0; final rect = Rect.fromLTWH( component.position.x.toDouble() - size / 2, component.position.y.toDouble() - size / 2, size, size, ); canvas.drawRect(rect, paint); } void _drawSelectionRect(Canvas canvas) { if (selectionRect == null) return; final fillPaint = Paint() ..color = const Color(0xFF2196F3).withOpacity(0.2) ..style = PaintingStyle.fill; final borderPaint = Paint() ..color = const Color(0xFF2196F3) ..strokeWidth = 1.0 ..style = PaintingStyle.stroke; canvas.drawRect(selectionRect!, fillPaint); canvas.drawRect(selectionRect!, borderPaint); } void _drawWiringLine(Canvas canvas) { if (wiringState == null) return; final paint = Paint() ..color = const Color(0xFFFF9800) ..strokeWidth = 2.0 ..style = PaintingStyle.stroke; final start = wiringState!.startPoint; if (start.position != null) { canvas.drawLine( Offset(start.position!.x.toDouble(), start.position!.y.toDouble()), wiringState!.currentPoint, paint, ); } } @override bool shouldRepaint(covariant DynamicLayerPainter oldDelegate) { return oldDelegate.wiringState != wiringState || oldDelegate.selectionRect != selectionRect || oldDelegate.hoveredComponent != hoveredComponent; } } // ============================================================================ // 3. GPU 加速利用 // ============================================================================ /// GPU 加速的元件渲染器 class GPUAcceleratedRenderer { /// 使用 PictureRecorder 批量录制绘制命令 static ui.Picture batchRenderComponents( List components, Size canvasSize, ) { final recorder = ui.PictureRecorder(); final canvas = Canvas(recorder); final bodyPaint = Paint() ..color = const Color(0xFF333333) ..style = PaintingStyle.stroke ..strokeWidth = 2.0; const size = 40.0; // 批量绘制所有元件 for (final component in components) { final rect = Rect.fromLTWH( component.position.x.toDouble() - size / 2, component.position.y.toDouble() - size / 2, size, size, ); canvas.drawRect(rect, bodyPaint); // 批量绘制引脚 for (final pin in component.pins) { final pinX = (component.position.x + pin.x).toDouble(); final pinY = (component.position.y + pin.y).toDouble(); canvas.drawCircle(Offset(pinX, pinY), 4.0, bodyPaint); } } return recorder.endRecording(); } /// 使用 Shader 实现渐变效果 static Shader createGradientShader(Offset start, Offset end) { return ui.Gradient.linear( start, end, [ const Color(0xFF2196F3), const Color(0xFF64B5F6), ], ); } /// 使用 ImageFilter 实现模糊效果 static ui.ImageFilter createBlurFilter(double sigma) { return ui.ImageFilter.blur(sigmaX: sigma, sigmaY: sigma); } /// 使用 ColorFilter 实现色调调整 static ui.ColorFilter createColorFilter() { return ui.ColorFilter.matrix([ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, ]); } } // ============================================================================ // 4. 辅助类 // ============================================================================ /// 预计算的元件数据 class _PrecomputedComponent { final ID id; final Offset position; final int rotation; final String name; final List pins; _PrecomputedComponent({ required this.id, required this.position, required this.rotation, required this.name, required this.pins, }); } /// 预计算的网络数据 class _PrecomputedNet { final ID id; final List points; _PrecomputedNet({ required this.id, required this.points, }); } /// 连线状态(与 editable_canvas.dart 保持一致) class WiringState { final ConnectionPoint startPoint; final Offset currentPoint; final NetType netType; const WiringState({ required this.startPoint, required this.currentPoint, this.netType = NetType.signal, }); } // ============================================================================ // 5. 性能监控 // ============================================================================ /// 渲染性能监控器 class RenderPerformanceMonitor { final List _frameTimes = []; final List _paintTimes = []; DateTime? _lastFrameTime; /// 标记帧开始 void markFrameStart() { final now = DateTime.now(); if (_lastFrameTime != null) { final frameTime = now.difference(_lastFrameTime!).inMilliseconds; _frameTimes.add(frameTime); if (_frameTimes.length > 300) { _frameTimes.removeAt(0); } } _lastFrameTime = now; } /// 标记绘制时间 void markPaintTime(int milliseconds) { _paintTimes.add(milliseconds); if (_paintTimes.length > 100) { _paintTimes.removeAt(0); } } /// 获取平均 FPS double get averageFPS { if (_frameTimes.isEmpty) return 0.0; final avgFrameTime = _frameTimes.reduce((a, b) => a + b) / _frameTimes.length; return avgFrameTime > 0 ? 1000.0 / avgFrameTime : 0.0; } /// 获取平均绘制时间 int get averagePaintTime { if (_paintTimes.isEmpty) return 0; return _paintTimes.reduce((a, b) => a + b) ~/ _paintTimes.length; } /// 获取性能报告 PerformanceReport get report => PerformanceReport( averageFPS: averageFPS, averagePaintTime: averagePaintTime, frameTimeP50: _percentile(_frameTimes, 50), frameTimeP95: _percentile(_frameTimes, 95), frameTimeP99: _percentile(_frameTimes, 99), ); int _percentile(List sortedData, int percentile) { if (sortedData.isEmpty) return 0; final sorted = List.from(sortedData)..sort(); final index = (sorted.length * percentile / 100).floor(); return sorted[index.clamp(0, sorted.length - 1)]; } void reset() { _frameTimes.clear(); _paintTimes.clear(); _lastFrameTime = null; } } /// 性能报告 class PerformanceReport { final double averageFPS; final int averagePaintTime; final int frameTimeP50; final int frameTimeP95; final int frameTimeP99; PerformanceReport({ required this.averageFPS, required this.averagePaintTime, required this.frameTimeP50, required this.frameTimeP95, required this.frameTimeP99, }); @override String toString() { return ''' 性能报告: 平均 FPS: ${averageFPS.toStringAsFixed(1)} 平均绘制时间:${averagePaintTime}ms 帧时间 P50: ${frameTimeP50}ms 帧时间 P95: ${frameTimeP95}ms 帧时间 P99: ${frameTimeP99}ms '''; } } // ============================================================================ // 6. 使用示例 // ============================================================================ /* /// 在 EditableCanvas 中使用分层渲染 class OptimizedEditableCanvas extends StatefulWidget { final Design design; final Function(Design) onDesignChanged; final SelectionManager selectionManager; const OptimizedEditableCanvas({ required this.design, required this.onDesignChanged, required this.selectionManager, }); @override State createState() => _OptimizedEditableCanvasState(); } class _OptimizedEditableCanvasState extends State { final RenderPerformanceMonitor _performanceMonitor = RenderPerformanceMonitor(); double _zoomLevel = 1.0; Offset _offset = Offset.zero; @override Widget build(BuildContext context) { _performanceMonitor.markFrameStart(); return GestureDetector( onScaleUpdate: _handleScaleUpdate, onPanUpdate: _handlePanUpdate, child: LayeredRenderer( design: widget.design, zoomLevel: _zoomLevel, offset: _offset, selectionManager: widget.selectionManager, ), ); } void _handleScaleUpdate(ScaleUpdateDetails details) { setState(() { _zoomLevel = (_zoomLevel * details.scale).clamp(0.1, 10.0); _offset += details.focalPoint - _lastPanPosition!; }); // 打印性能数据 if (_performanceMonitor.averageFPS < 30) { debugPrint('⚠️ 性能警告:FPS = ${_performanceMonitor.averageFPS.toStringAsFixed(1)}'); } } } */