From f638ef23dedfe95bf5141b15f874e1594db0e0dd Mon Sep 17 00:00:00 2001 From: "DESKTOP-I3JPKHK\\wy" <1111> Date: Mon, 15 Sep 2025 15:31:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=8F=90=E4=BA=A4=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=95=99=E7=99=BD=E5=8C=BA=E5=9F=9F=E7=AC=94?= =?UTF-8?q?=E8=BF=B9=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/question_paper_view.dart | 118 +++++++++--------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart index 7501014..a4c22fa 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart @@ -1,6 +1,4 @@ import 'dart:async'; -import 'dart:io'; -import 'dart:math'; import 'package:flutter/cupertino.dart' hide TransformationController; import 'package:flutter/material.dart'; @@ -17,6 +15,7 @@ import 'package:making_school_asignment_app/common/utils/cached_network_img.dart import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; +import 'package:vector_math/vector_math_64.dart' show Vector3, Matrix4; import 'package:zoom_widget/zoom_widget.dart'; import '../configuration_files/zoom_logic.dart'; @@ -299,25 +298,11 @@ class QuestionImageView extends HookWidget with EventBusMixin> vnHandWritings) { - timer?.cancel(); - timer = Timer(const Duration(milliseconds: timeoutDuration), () { - if (_activePointers > 2) { - _activePointers = 0; - if (vnHandWritings.value.isNotEmpty && vnHandWritings.value.last != null) { - vnHandWritings.value.add(null); // 增加空点以分隔不同的线段 - sateData.handwritings = vnHandWritings.value; // 添加笔迹数据 - } - } - }); - } + /// 注意:实际逻辑在 build 内部基于 useRef 管理,避免可变实例字段 /// 获取最后一个点的坐标位置 Offset? getLastDrop(List vals, int index) { @@ -338,6 +323,23 @@ class QuestionImageView extends HookWidget with EventBusMixin(0); + final timerRef = useRef(null); + + void startTimerForHandwriting(ValueNotifier> vnHandWritings) { + timerRef.value?.cancel(); + timerRef.value = Timer(const Duration(milliseconds: timeoutDuration), () { + if (activePointers.value > 2) { + activePointers.value = 0; + if (vnHandWritings.value.isNotEmpty && vnHandWritings.value.last != null) { + vnHandWritings.value.add(null); // 增加空点以分隔不同的线段 + sateData.handwritings = vnHandWritings.value; // 添加笔迹数据 + } + } + }); + } + final theMaxHeight = useState(maxHeight); useValueChanged(maxHeight, (oldValue, __) => theMaxHeight.value = maxHeight); @@ -477,7 +479,8 @@ class QuestionImageView extends HookWidget with EventBusMixin 0) { - _activePointers = _activePointers - 1; + if (activePointers.value > 0) { + activePointers.value = activePointers.value - 1; } - print("---进入:onPointerUp $_activePointers"); - timer?.cancel(); + print("---进入:onPointerUp ${activePointers.value}"); + timerRef.value?.cancel(); if (!annotationState.pen.value) return; vnHandWritings.value.add(null); // 增加空点以分隔不同的线段 sateData.handwritings = vnHandWritings.value; // 添加笔迹数据 }, onPointerMove: (PointerMoveEvent event) { - print("进入:onPointerMove $_activePointers"); - if (_activePointers != 1) return; - toTimer(vnHandWritings); + print("进入:onPointerMove ${activePointers.value}"); + if (activePointers.value != 1) return; + startTimerForHandwriting(vnHandWritings); if (!annotationState.pen.value) return; Offset localPosition = event.localPosition; // 相对 - var zoomFile = zoomState.zoomFile.value!; - // var imageHeightOffsetStart = zoomFile.imageHeightOffsetStart??0; - var imageHeightOffsetStart = zoomState.zoomFile.value!.getZoomFileOffsetStart(zoomState.initScale.value ?? 1); - // print("位置:$localPosition; 图片所在位置:$imageHeightOffsetStart"); - if (imageHeightOffsetStart == 0) return; - var dy = localPosition.dy; - // print(zoomFile.getZoomFileHeightOffsetEnd(zoomState.initScale.value ?? 1)); - if (dy < imageHeightOffsetStart || dy > zoomFile.getZoomFileHeightOffsetEnd(zoomState.initScale.value ?? 1)) { - return; // 检查笔记是否超出图片范围 - } - - var theScale = zoomState.initScale.value ?? 1; + // 使用矩阵进行统一坐标反算(避免重复补偿) + final Matrix4 matrix = logic.zoomController.value; // 当前变换矩阵 + final double theScale = matrix.getMaxScaleOnAxis(); // if (theScale != 1) { // print("PPPPPPPPPPPPPPPPPPPPPPPP ${(zoomFile.imageHeightOffsetStart ?? 0)}"); // localPosition = Offset(localPosition.dx, localPosition.dy + (zoomFile.imageHeightOffsetStart ?? 0)); @@ -549,26 +543,36 @@ class QuestionImageView extends HookWidget with EventBusMixin 图片坐标(通过逆矩阵) + final inv = Matrix4.inverted(matrix); + final v = inv.transform3(Vector3(localPosition.dx, localPosition.dy, 0)); + localPosition = Offset(v.x, v.y); - // 优先使用变换矩阵获得当前内容平移(有符号,右/下为正,左/上为负) - final translation = logic.zoomController.value.getTranslation(); - final panDx = translation.x; - final panDy = translation.y; + // 在图片坐标系做边界校验(更直观):0..maxWidth、0..actualHeight + if (localPosition.dy < 0 || localPosition.dy > actualHeight) return; + if (localPosition.dx < 0 || localPosition.dx > maxWidth) return; - // 将屏幕触点换算到图片坐标:先去除图片在容器中的留白,再减去内容平移,最后按缩放反算 - final correctedDx = (localPosition.dx - leftOffset - panDx) / theScale; - final correctedDy = (dy - topOffset - panDy) / theScale; - localPosition = Offset(correctedDx, correctedDy); + /// 判断当前点和上一个点的距离: + /// - 跨平台跳变过滤(自适应缩放阈值) + /// - 同时加入最小采样间距,降采样以减少噪点与性能压力 + var lastDrop = getLastDrop(vnHandWritings.value, vnHandWritings.value.length - 1); + if (lastDrop != null) { + const double baseJump = 65.0; + final double jumpThreshold = baseJump / theScale; + if ((lastDrop.dx - localPosition.dx).abs() > jumpThreshold || + (lastDrop.dy - localPosition.dy).abs() > jumpThreshold) { + return; // 多指/跳变判定 + } + } - /// 判断当前点和上一个点的距离 判断是否是多指 - if (Platform.isAndroid) { - var lastDrop = getLastDrop(vnHandWritings.value, vnHandWritings.value.length - 1); - if (lastDrop != null && - ((lastDrop.dx - localPosition.dx).abs() > 65 || (lastDrop.dy - localPosition.dy).abs() > 65)) { - /// 当前X点和上一个x点相差 大于10判定为多个手指 - return; + // 最小采样间距(随缩放反向缩放) + if (lastDrop != null) { + const double baseDist = 1.6; // 基础距离 + final double minDist = baseDist / theScale; + final double dx = localPosition.dx - lastDrop.dx; + final double dy = localPosition.dy - lastDrop.dy; + if ((dx * dx + dy * dy) < (minDist * minDist)) { + return; // 距离过近,忽略本次点 } } // print("最终位置 : $localPosition"); @@ -576,9 +580,7 @@ class QuestionImageView extends HookWidget with EventBusMixin