diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_number_view.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_number_view.dart index 64985c9..0a76601 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_number_view.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_number_view.dart @@ -106,7 +106,8 @@ Widget $questionNumberScrollView({ /// 无法联动 // if (sateData.panQuestView == false) sateData.slide.value = scrollControllerNum.offset; - final currentMatrix = controller.zoomController.value; + final currentMatrix = controller.zoomController?.value; + if (currentMatrix == null) return; // 创建一个新的变换矩阵,只修改垂直平移分量 final newMatrix = Matrix4.copy(currentMatrix) @@ -116,7 +117,7 @@ Widget $questionNumberScrollView({ currentMatrix.getTranslation().z, // 保持 Z 轴不变 )); - controller.zoomController.value = newMatrix; + controller.zoomController?.value = newMatrix; }); var listenVal = sateData.slide.listen((e) { if (sateData.panQuestView != null && sateData.panQuestView == true && e != scrollControllerNum.offset) { 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 a4c22fa..a4e76e7 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 @@ -46,10 +46,10 @@ class QuestionPaperView extends GetView { if (zoomFileModel == null) { /// 计算高度 return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { - WidgetsBinding.instance.addPostFrameCallback((_) => zoomState.zoomFile.value = ZoomFileModel( - viewWidth: constraints.maxWidth, - viewHeight: constraints.maxHeight, - )); + WidgetsBinding.instance.addPostFrameCallback( + (_) => zoomState.zoomFile.value = + ZoomFileModel(viewWidth: constraints.maxWidth, viewHeight: constraints.maxHeight), + ); return const SizedBox(); }); } @@ -345,7 +345,18 @@ class QuestionImageView extends HookWidget with EventBusMixin(GlobalKey()); useValueChanged(zoomState.zoomFile.value?.templateId, (old, __) { - zoomKey.value = GlobalKey(); + // 延迟重建Zoom组件,确保重置完成后再重建 + WidgetsBinding.instance.addPostFrameCallback((_) { + zoomKey.value = GlobalKey(); + + // 重建后再次设置居中矩阵,确保居中状态不被覆盖 + WidgetsBinding.instance.addPostFrameCallback((_) { + final double offsetY = (zoomState.zoomFile.value?.imageHeightOffsetStart ?? 0).toDouble(); + if (offsetY > 0) { + logic.zoomController?.value = Matrix4.identity()..setTranslationRaw(0, offsetY, 0); + } + }); + }); }); var vnHandWritings = useValueNotifier>([]); @@ -523,7 +534,7 @@ class QuestionImageView extends HookWidget with EventBusMixin Zoom( - key: zoomKey.value, - // initTotalZoomOut: true, // 展示全部内容 初始化不产生滚动条 - zoomSensibility: 0.05, - scrollWeight: 4.r, - doubleTapAnimDuration: Duration.zero, - maxZoomWidth: maxWidth, - maxZoomHeight: actualHeight, - canvasColor: Colors.transparent, - doubleTapScaleChange: 1, - // initPosition: initPosition.value, - // initScale: logic.zoomLogic.zoomState.initScale.value ?? 1, - backgroundColor: Colors.transparent, - onScaleUpdate: (double scale, double zoom) => logic.zoomLogic.onScaleUpdate(zoom), - onPositionUpdate: logic.zoomLogic.onPanUpPosition, - transformationController: logic.zoomController, - child: Stack( - children: [ - $TheCachedNetworkImage( - imgWidth: maxWidth, - imageUrl: sateData.data.value!.zgtAnswer, - (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), + // 仅当“滑动试题”启用时,让 Zoom 接收触摸;否则屏蔽以避免与批注冲突 + ignoring: !annotationState.gestureMove.value, + child: Zoom( + key: zoomKey.value, + // initTotalZoomOut: true, // 展示全部内容 初始化不产生滚动条 + zoomSensibility: 0.05, + scrollWeight: 4.r, + doubleTapAnimDuration: Duration.zero, + maxZoomWidth: maxWidth, + maxZoomHeight: actualHeight, + canvasColor: Colors.transparent, + doubleTapScaleChange: 1, + initScale: 1, + backgroundColor: Colors.transparent, + // onScaleUpdate: (double scale, double zoom) => logic.zoomLogic.onScaleUpdate(zoom), + // onPositionUpdate: logic.zoomLogic.onPanUpPosition, + transformationController: logic.zoomController, + child: Obx(() { + return Stack( + children: [ + $TheCachedNetworkImage( + imgWidth: maxWidth, + imageUrl: sateData.data.value!.zgtAnswer, + (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), + ), + RepaintBoundary( + key: logic.pictureOverviewKey, + child: CustomPaint( + // isComplex: true, + size: Size(maxWidth, actualHeight), + foregroundPainter: DrawingPainter(ctrl: vnHandWritings), + // child: $TheCachedNetworkImage( + // imgWidth: maxWidth, + // imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer, + // (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), + // ), + child: showZgtAnnotate != null + ? $TheCachedNetworkImage( + imgWidth: maxWidth, + imageUrl: showZgtAnnotate, + (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth)) + : null, ), - RepaintBoundary( - key: logic.pictureOverviewKey, - child: CustomPaint( - // isComplex: true, - size: Size(maxWidth, actualHeight), - foregroundPainter: DrawingPainter(ctrl: vnHandWritings), - // child: $TheCachedNetworkImage( - // imgWidth: maxWidth, - // imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer, - // (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), - // ), - child: showZgtAnnotate != null - ? $TheCachedNetworkImage( - imgWidth: maxWidth, - imageUrl: showZgtAnnotate, - (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth)) - : null, - ), - ), - ], - ), - ), - )), + ), + ], + ); + }), + ), + ), ); }), ); diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart index d82baea..24937b5 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart @@ -83,7 +83,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus StreamSubscription? imageScaleZoomStream; - late final zoomWidget.TransformationController zoomController; + zoomWidget.TransformationController? zoomController; @override void onInit() { @@ -105,15 +105,6 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus // 试题数据 _dataListen = state.data.listen((e) { if (e == null) return; - var zoomState = zoomLogic.zoomState; - - final currentTemplateId = zoomState.zoomFile.value?.templateId; // 获取旧题号ID - if (currentTemplateId != null && currentTemplateId != e.templateId) { - // zoom 题号判断是否有变 有变就需要清空 zoom文件 - zoomState.initScale.value = null; - zoomState.zoomFile.value!.clearZoomFile(e.templateId); - zoomState.zoomFile.update((_) {}); // 更新的是对象 需要执行此回调 - } if (state.favorite.value != e.isFav) state.favorite.value = !state.favorite.value; }); @@ -147,7 +138,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus @override void onClose() { - zoomController.dispose(); + zoomController?.dispose(); // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); // 屏幕刘海 eventCancel(); _dataListen.cancel(); diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/zoom_logic.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/zoom_logic.dart index 0f52db7..f8da892 100644 --- a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/zoom_logic.dart +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/zoom_logic.dart @@ -17,47 +17,44 @@ class ZoomLogic extends GetxController { ); var oldTemplateId; - late StreamSubscription _streamHomework; - late StreamSubscription _streamZoomState; + StreamSubscription? _streamHomework; + StreamSubscription? _streamZoomState; StreamSubscription? initScaleStream; + Map imageSizeMap = {}; + + HomeworkReviewLogic get homeworkReviewLogic => Get.find(); + @override void onInit() { oldTemplateId = zoomState.zoomFile.value?.templateId; /// 根据第一次加载的试题题号 分析试题图片所占的宽高 - _streamZoomState = zoomState.zoomFile.listen((e) { - var templateId = e?.templateId; - if (templateId == null) return; - - var homeworkData = Get.find().state.data.value; - var zgtAnswer = homeworkData?.zgtAnswer; - if (zgtAnswer == null) return; - if (oldTemplateId == templateId) return; - - // getNetworkImageDimensions(zgtAnswer); - - // 第三方库网络图,图片会被解码并缓存于内存 - oldTemplateId = templateId; - CachedNetworkImageProvider(zgtAnswer).getImageSize().then((s) { - // 提取宽度和高度 - if (s == null) return; - var oldVal = zoomState.zoomFile.value!; - oldVal.fileWidth = s.width; - oldVal.fileHeight = s.height; - zoomState.zoomFile.value = ZoomFileModel.fromJson(oldVal.toJson()); - }); - }); + _streamZoomState = zoomState.zoomFile.listen((e) => refreshZoomFile(e)); WidgetsBinding.instance.addPostFrameCallback((e) { /// 试题加载后更新尺寸对象(只要题号没有变就不更新尺寸对象) - _streamHomework = Get.find().state.data.listen((e) { + _streamHomework = homeworkReviewLogic.state.data.listen((e) { print("HOMEWORKSTATE 变化了"); - if (e == null || zoomState.zoomFile.value == null) return; - zoomState.zoomFile.value!.templateId = e.templateId; - print("666666 ${e.templateId}"); - zoomState.zoomFile.value = ZoomFileModel.fromJson(zoomState.zoomFile.value!.toJson()); + var zoomFile = zoomState.zoomFile.value; + if (e == null || zoomFile == null) return; + + if (zoomFile.templateId != e.templateId) { + // zoom 题号判断是否有变 有变就需要清空 zoom文件 + zoomState.initScale.value = null; + zoomFile = ZoomFileModel( + templateId: e.templateId, + viewWidth: zoomFile.viewWidth, + viewHeight: zoomFile.viewHeight, + ); + + /// 重置缩放和位置 + _resetZoom(); + } + + /// 更新尺寸对象 + refreshZoomFile(zoomFile); }); }); @@ -69,11 +66,51 @@ class ZoomLogic extends GetxController { @override void onClose() { - _streamHomework.cancel(); - _streamZoomState.cancel(); + _streamHomework?.cancel(); + _streamZoomState?.cancel(); super.onClose(); } + void refreshZoomFile(ZoomFileModel? e) { + var templateId = e?.templateId; + if (templateId == null) return; + + var homeworkData = homeworkReviewLogic.state.data.value; + var zgtAnswer = homeworkData?.zgtAnswer; + if (zgtAnswer == null || oldTemplateId == templateId) return; + + // getNetworkImageDimensions(zgtAnswer); + + oldTemplateId = templateId; + final fileSize = imageSizeMap[templateId]; + print("fileSize: ${fileSize?.toJson()}"); + if (fileSize != null) { + zoomState.zoomFile.value = fileSize; + return; + } + + /// 第三方库网络图,图片会被解码并缓存于内存 + CachedNetworkImageProvider(zgtAnswer).getImageSize().then((s) { + if (s == null) return; + + // 提取宽度和高度 + var oldZoomFile = zoomState.zoomFile.value!; + + /// 重置部分数据 避免数据被覆盖 + var newZoomFile = ZoomFileModel( + templateId: templateId, + viewWidth: oldZoomFile.viewWidth, + viewHeight: oldZoomFile.viewHeight, + fileWidth: s.width, + fileHeight: s.height, + ); + + /// 初始化zoom文件 + imageSizeMap[templateId] = newZoomFile; + zoomState.zoomFile.value = newZoomFile; + }); + } + // 缩放组件 ==> 缩放监听 void onScaleUpdate(double zoom) async { print("缩放比例:$zoom"); @@ -86,12 +123,34 @@ class ZoomLogic extends GetxController { // 缩放组件 ==> 位置更新 void onPanUpPosition(Offset val) async { // 手指在移动 非物体移动的位置 - var state = Get.find().state; + var state = homeworkReviewLogic.state; print('**************** 正在移动位置 YYY:${val.dy}'); print('**************** 正在移动位置 XXX:${val.dx}'); state.zoomOffset = val; state.slide.value = val.dy.abs().toInt().toDouble(); } + + // 重置缩放和位置 + void _resetZoom() { + // 重置缩放状态 + zoomState.initScale.value = 1.0; + + // 重置位置偏移 + homeworkReviewLogic.state.zoomOffset = Offset.zero; + homeworkReviewLogic.state.slide.value = 0.0; + + // final zoomFile = zoomState.zoomFile.value; + // final double imageOffsetY = (zoomFile?.imageHeightOffsetStart ?? 0).toDouble(); + // final controller = homeworkReviewLogic.zoomController; + // if (controller != null) { + // // 以单位矩阵为基,设置垂直平移到居中位置 + // final Matrix4 centered = Matrix4.identity()..setTranslationRaw(0, imageOffsetY > 0 ? imageOffsetY : 0, 0); + + // controller.value = centered; + // } + + print('缩放已重置'); + } } class HomeworkReviewZoomBinding extends Bindings { @@ -143,18 +202,19 @@ class ZoomFileModel extends Object { this.imageHeightOffsetend, this.pixelRatio, }) { + /// 初始化尺寸信息 // 图片已视图宽为基准,高度自适应可滑动 图片的实际宽高都需要乘此基准值. - if (fileHeight == null || fileWidth == null) return; + if (fileHeight != null && fileWidth != null) { + scaleRatio = viewWidth / fileWidth!; + actualWidth = fileWidth! * scaleRatio; + actualHeight = fileHeight! * scaleRatio; - scaleRatio = viewWidth / fileWidth!; - actualWidth = fileWidth! * scaleRatio; - actualHeight = fileHeight! * scaleRatio; + pixelRatio = fileWidth! / viewWidth; // 图片在此设备的像素比例 - pixelRatio = fileWidth! / viewWidth; // 图片在此设备的像素比例 - - remainingHeight = viewHeight - actualHeight!; - imageHeightOffsetStart = remainingHeight! / 2; - imageHeightOffsetend = imageHeightOffsetStart! + actualHeight!; + remainingHeight = viewHeight - actualHeight!; + imageHeightOffsetStart = remainingHeight! / 2; + imageHeightOffsetend = imageHeightOffsetStart! + actualHeight!; + } } factory ZoomFileModel.fromJson(Map srcJson) => _$ZoomFileModelFromJson(srcJson); diff --git a/making_school_asignment_app/pubspec.yaml b/making_school_asignment_app/pubspec.yaml index 3f377a9..9f5d474 100644 --- a/making_school_asignment_app/pubspec.yaml +++ b/making_school_asignment_app/pubspec.yaml @@ -48,7 +48,7 @@ dependencies: # http请求插件 dio: ^5.4.2+1 # 网络缓存图片 - cached_network_image: ^3.2.1 + cached_network_image: ^3.4.1 # 上拉加载和下拉刷新的组件 flutter_easyrefresh: ^2.2.2 photo_view: ^0.15.0 @@ -94,7 +94,7 @@ dependencies: flutter_spinkit: ^5.2.1 event_bus: ^2.0.0 path_provider: ^2.1.3 - uuid: ^3.0.7 + flutter_echarts: ^2.4.0 # 饼图 flutter_echart: ^2.0.0 @@ -112,6 +112,7 @@ dependencies: dependency_overrides: archive: ^4.0.2 + uuid: ^4.4.2 # meta: ^1.15.0 dev_dependencies: