feat(homework_review): 优化批注绘制与坐标换算,提升交互流畅度
- 批注绘制改为 Path 聚合一次性绘制 - 移除高频 print,开启 CustomPaint isComplex/willChange - 无变换时跳过逆矩阵 - 回滚不必要的 RepaintBoundary/低过滤 - 调整 Path 判空判断写法
This commit is contained in:
parent
1fc54d7526
commit
c7afafc3aa
|
|
@ -518,7 +518,7 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
|
|||
if (activePointers.value > 0) {
|
||||
activePointers.value = activePointers.value - 1;
|
||||
}
|
||||
print("---进入:onPointerUp ${activePointers.value}");
|
||||
// 移除高频日志,避免导致掉帧
|
||||
timerRef.value?.cancel();
|
||||
if (!annotationState.pen.value) return;
|
||||
|
||||
|
|
@ -526,7 +526,7 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
|
|||
sateData.handwritings = vnHandWritings.value; // 添加笔迹数据
|
||||
},
|
||||
onPointerMove: (PointerMoveEvent event) {
|
||||
print("进入:onPointerMove ${activePointers.value}");
|
||||
// 移除高频日志,避免导致掉帧
|
||||
if (activePointers.value != 1) return;
|
||||
startTimerForHandwriting(vnHandWritings);
|
||||
if (!annotationState.pen.value) return;
|
||||
|
|
@ -555,9 +555,24 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
|
|||
// (dy / theScale) - (max(0, imageHeightOffsetStart) / theScale) + ((sateData.zoomOffset?.dy.abs() ?? 0) / theScale),
|
||||
|
||||
// 屏幕坐标 -> 图片坐标(通过逆矩阵)
|
||||
final inv = Matrix4.inverted(matrix);
|
||||
final v = inv.transform3(Vector3(localPosition.dx, localPosition.dy, 0));
|
||||
localPosition = Offset(v.x, v.y);
|
||||
// final inv = Matrix4.inverted(matrix);
|
||||
// final v = inv.transform3(Vector3(localPosition.dx, localPosition.dy, 0));
|
||||
// localPosition = Offset(v.x, v.y);
|
||||
|
||||
/// 屏幕坐标 -> 图片坐标(通过逆矩阵)。当无缩放/平移时走快速路径,避免不必要求逆
|
||||
/// 它们是 Matrix4 内部 4x4 矩阵的平移分量(列主序存储)。
|
||||
/// storage[12] 是平移的 x 分量,storage[13] 是平移的 y 分量(storage[14] 则是 z)。
|
||||
/// 因为 Matrix4 采用列主序,索引计算为 index = col * 4 + row,平移在第 4 列的前 3 行,所以是 12、13、14。
|
||||
/// 用途:当 theScale == 1.0 && storage[12] == 0.0 && storage[13] == 0.0 时,可判定无缩放/平移,走快速路径跳过逆矩阵。
|
||||
final double tx = matrix.storage[12];
|
||||
final double ty = matrix.storage[13];
|
||||
if (theScale == 1.0 && tx == 0.0 && ty == 0.0) {
|
||||
// identity 变换,局部坐标无需转换
|
||||
} else {
|
||||
final inv = Matrix4.inverted(matrix);
|
||||
final v = inv.transform3(Vector3(localPosition.dx, localPosition.dy, 0));
|
||||
localPosition = Offset(v.x, v.y);
|
||||
}
|
||||
|
||||
// 在图片坐标系做边界校验(更直观):0..maxWidth、0..actualHeight
|
||||
if (localPosition.dy < 0 || localPosition.dy > actualHeight) return;
|
||||
|
|
@ -625,7 +640,8 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
|
|||
RepaintBoundary(
|
||||
key: logic.pictureOverviewKey,
|
||||
child: CustomPaint(
|
||||
// isComplex: true,
|
||||
isComplex: true,
|
||||
willChange: true,
|
||||
size: Size(maxWidth, actualHeight),
|
||||
foregroundPainter: DrawingPainter(ctrl: vnHandWritings),
|
||||
// child: $TheCachedNetworkImage(
|
||||
|
|
@ -658,19 +674,40 @@ class DrawingPainter extends CustomPainter {
|
|||
final Paint paintBrush = Paint()
|
||||
..color = Colors.red
|
||||
..strokeCap = StrokeCap.round
|
||||
..strokeWidth = 0.7.sp;
|
||||
..strokeJoin = StrokeJoin.round
|
||||
..isAntiAlias = true
|
||||
..strokeWidth = 0.7.sp
|
||||
..style = PaintingStyle.stroke;
|
||||
DrawingPainter({required this.ctrl}) : super(repaint: ctrl);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
var points = ctrl.value;
|
||||
var pointsLength = points.length;
|
||||
for (int i = 0; i < pointsLength; i++) {
|
||||
Offset? offsetData = points[i];
|
||||
Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1];
|
||||
if (offsetData != null && nextOffsetData != null) {
|
||||
canvas.drawLine(offsetData, nextOffsetData, paintBrush);
|
||||
final List<dynamic> points = ctrl.value;
|
||||
if (points.isEmpty) return;
|
||||
|
||||
Path path = Path();
|
||||
Offset? previous;
|
||||
for (int i = 0; i < points.length; i++) {
|
||||
final Offset? current = points[i] as Offset?;
|
||||
if (current == null) {
|
||||
// 提交当前子路径
|
||||
if (path.computeMetrics().isNotEmpty) {
|
||||
canvas.drawPath(path, paintBrush);
|
||||
}
|
||||
path = Path();
|
||||
previous = null;
|
||||
continue;
|
||||
}
|
||||
if (previous == null) {
|
||||
path.moveTo(current.dx, current.dy);
|
||||
} else {
|
||||
path.lineTo(current.dx, current.dy);
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
// 绘制最后的子路径
|
||||
if (path.computeMetrics().isNotEmpty) {
|
||||
canvas.drawPath(path, paintBrush);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue