mobile-eda/lib/core/optimization/render_optimization.dart

886 lines
23 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 渲染优化方案 - 实现代码
*
* 优化策略:
* 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<LayeredRenderer> createState() => _LayeredRendererState();
}
class _LayeredRendererState extends State<LayeredRenderer> {
// 静态层控制器
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 = <Offset>[];
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 = <Offset>[];
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 = <Offset>[];
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<Component> 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<Offset> pins;
_PrecomputedComponent({
required this.id,
required this.position,
required this.rotation,
required this.name,
required this.pins,
});
}
/// 预计算的网络数据
class _PrecomputedNet {
final ID id;
final List<Offset> 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<int> _frameTimes = [];
final List<int> _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<int> sortedData, int percentile) {
if (sortedData.isEmpty) return 0;
final sorted = List<int>.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<OptimizedEditableCanvas> createState() => _OptimizedEditableCanvasState();
}
class _OptimizedEditableCanvasState extends State<OptimizedEditableCanvas> {
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)}');
}
}
}
*/