补充提交,修复留白区域笔迹问题
This commit is contained in:
parent
8fd6c57874
commit
f638ef23de
|
|
@ -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<BottomOperationBar
|
|||
return -1;
|
||||
}
|
||||
|
||||
int _activePointers = 0;
|
||||
|
||||
Timer? timer;
|
||||
// 定时器超时时间,单位为毫秒
|
||||
static const int timeoutDuration = 300;
|
||||
|
||||
/// 解决多指截屏问题后 无法进入手指抬起回调导致无法再次进行批注
|
||||
void toTimer(ValueNotifier<List<dynamic>> 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<dynamic> vals, int index) {
|
||||
|
|
@ -338,6 +323,23 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 管理触点数量与定时器(避免在 HookWidget 中使用可变实例字段)
|
||||
final activePointers = useRef<int>(0);
|
||||
final timerRef = useRef<Timer?>(null);
|
||||
|
||||
void startTimerForHandwriting(ValueNotifier<List<dynamic>> 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<double>(maxHeight);
|
||||
useValueChanged<double, void>(maxHeight, (oldValue, __) => theMaxHeight.value = maxHeight);
|
||||
|
||||
|
|
@ -477,7 +479,8 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
|
|||
});
|
||||
|
||||
return () {
|
||||
_activePointers = 0;
|
||||
activePointers.value = 0;
|
||||
timerRef.value?.cancel();
|
||||
eventCancel();
|
||||
};
|
||||
}, []);
|
||||
|
|
@ -491,46 +494,37 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
|
|||
// 判断当前是否已经有触摸点,如果有则忽略该触摸事件
|
||||
|
||||
// 处理单个触摸点按下的逻辑
|
||||
_activePointers = _activePointers + 1;
|
||||
activePointers.value = activePointers.value + 1;
|
||||
|
||||
/// 解决多指截屏问题后 无法进入手指抬起回调导致无法再次进行批注
|
||||
toTimer(vnHandWritings);
|
||||
startTimerForHandwriting(vnHandWritings);
|
||||
sateData.panQuestView = true;
|
||||
},
|
||||
onPointerUp: (PointerUpEvent details) {
|
||||
// 处理单个触摸点抬起的逻辑
|
||||
// activePointers--;
|
||||
// globalPosition = null;
|
||||
if (_activePointers > 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<BottomOperationBar
|
|||
// }
|
||||
// (dy / theScale) - (max(0, imageHeightOffsetStart) / theScale) + ((sateData.zoomOffset?.dy.abs() ?? 0) / theScale),
|
||||
|
||||
var leftOffset = zoomFile.getZoomFileOffsetStartWidth(theScale);
|
||||
var topOffset = max(0, imageHeightOffsetStart);
|
||||
// 屏幕坐标 -> 图片坐标(通过逆矩阵)
|
||||
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<BottomOperationBar
|
|||
sateData.handwritings = vnHandWritings.value;
|
||||
},
|
||||
child: Obx(() {
|
||||
var isPen = annotationState.pen.value;
|
||||
var showZgtAnnotate = sateData.data.value?.showZgtAnnotate;
|
||||
|
||||
return Container(
|
||||
height: double.infinity,
|
||||
width: double.infinity,
|
||||
|
|
|
|||
Loading…
Reference in New Issue