import 'dart:async'; import 'package:fis_i18n/i18n.dart'; import 'package:fis_measure/interfaces/process/items/item.dart'; import 'package:fis_measure/interfaces/process/workspace/application.dart'; import 'package:fis_measure/process/items/top_item.dart'; import 'package:fis_measure/process/workspace/application.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; class FineTunePanel extends StatefulWidget { final Size panelSize; const FineTunePanel({ Key? key, this.panelSize = const Size(150, 150), }) : super(key: key); @override State createState() => _FineTunePanelState(); } class _FineTunePanelState extends State { Application application = Get.find() as Application; final GlobalKey _magnifierKey = GlobalKey(); double arrowButtonSize = 50; Offset containerPos = const Offset(0, 0); Size containerSize = const Size(0, 0); bool ifShowPanel = false; bool ifSetTop = false; //是否置于顶部 static const double fineTuneStep = 0.001; bool isCombined = false; Timer? _timer; IMeasureItem? get _currWorkingItem => isCombined ? (application.activeMeasureItem as TopMeasureItem).workingChild : application.activeMeasureItem; @override void initState() { arrowButtonSize = widget.panelSize.width / 2.5; application.mobileTouchEndEvent.addListener(_onMobileTouchEndEvent); application.mobileTouchEvent.addListener(_onMobileTouchEvent); application.activeMeasureItemChanged .addListener(_onActiveMeasureItemChanged); WidgetsBinding.instance.addPostFrameCallback((_) => { _initContainerParam(), }); super.initState(); } @override void dispose() { application.mobileTouchEndEvent.removeListener(_onMobileTouchEndEvent); application.mobileTouchEvent.removeListener(_onMobileTouchEvent); application.activeMeasureItemChanged .removeListener(_onActiveMeasureItemChanged); super.dispose(); } @override Widget build(BuildContext context) { return Row( children: [ Column( mainAxisAlignment: ifSetTop ? MainAxisAlignment.start : MainAxisAlignment.end, children: [ if (ifShowPanel) Opacity( opacity: 0.7, child: Container( margin: EdgeInsets.only( left: 20, right: 20, top: ifSetTop ? 20 : 0, bottom: ifSetTop ? 0 : 20, ), decoration: BoxDecoration( border: Border.all(color: Colors.white, width: 2), borderRadius: BorderRadius.circular(10), color: Colors.black.withOpacity(0.8)), child: Column( children: [ Container( decoration: BoxDecoration( color: const Color.fromARGB(255, 53, 53, 53) .withOpacity(0.8), borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), )), width: widget.panelSize.width, child: Padding( padding: const EdgeInsets.all(3.0), child: Text( i18nBook.measure.fineTuneStartPoint.t, style: const TextStyle( color: Colors.white, fontSize: 14), textAlign: TextAlign.center, ), ), ), Container( height: 2, width: widget.panelSize.width, color: Colors.white, ), SizedBox( key: _magnifierKey, width: widget.panelSize.width, height: widget.panelSize.height, child: Stack( children: [ _buildFineTuneButton( Alignment.centerLeft, Icons.arrow_circle_left_outlined, const Offset(-1 * fineTuneStep, 0)), _buildFineTuneButton( Alignment.topCenter, Icons.arrow_circle_up_outlined, const Offset(0, -1 * fineTuneStep)), _buildFineTuneButton( Alignment.centerRight, Icons.arrow_circle_right_outlined, const Offset(fineTuneStep, 0)), _buildFineTuneButton( Alignment.bottomCenter, Icons.arrow_circle_down_outlined, const Offset(0, fineTuneStep)), ], ), ), ], ), ), ), ], ), ], ); } Align _buildFineTuneButton( Alignment alignment, IconData icon, Offset offset) { return Align( alignment: alignment, child: GestureDetector( onTapDown: (e) { _onTapFineTuneButton(offset); }, onLongPress: () { _startLongPressTimer(offset); }, onLongPressUp: () { _stopLongPressTimer(); }, child: Icon( icon, color: Colors.white, size: arrowButtonSize, ), ), ); } void _initContainerParam() { final containerLayer = context.findRenderObject() as RenderBox; containerPos = containerLayer.localToGlobal(Offset.zero); containerSize = containerLayer.size; } void _updateAlignment(Offset touchPos) { if (touchPos.dx < widget.panelSize.width) { if (ifSetTop && (touchPos.dy < containerSize.height / 2)) { setState(() { ifSetTop = false; }); } else if (!ifSetTop && (touchPos.dy > containerSize.height / 2)) { setState(() { ifSetTop = true; }); } } else if (ifSetTop) { setState(() { ifSetTop = false; }); } } void _onMobileTouchEndEvent(_, Offset offset) { isCombined = false; if (_currWorkingItem?.feature != null) { int pointsNum = 0; pointsNum = _currWorkingItem?.feature!.innerPoints.toSet().toList().length ?? 0; if (pointsNum == 1) { setState(() { ifShowPanel = true; }); Offset startPoint = application .activeMeasureItem!.feature!.innerPoints[0] .toOffset() .scale(containerSize.width, containerSize.height); _updateAlignment(startPoint); return; } if (application.activeMeasureItem is TopMeasureItem) { isCombined = true; if (_currWorkingItem?.feature != null) { pointsNum = _currWorkingItem!.feature!.innerPoints.toSet().toList().length; if (pointsNum == 1) { setState(() { ifShowPanel = true; }); Offset startPoint = _currWorkingItem!.feature!.innerPoints[0] .toOffset() .scale(containerSize.width, containerSize.height); _updateAlignment(startPoint); return; } } } } setState(() { ifShowPanel = false; }); } void _onMobileTouchEvent(_, Offset offset) { if (!ifShowPanel) return; setState(() { ifShowPanel = false; }); } void _onActiveMeasureItemChanged(_, IMeasureItem? item) { if (!ifShowPanel) return; setState(() { ifShowPanel = false; }); } void _onTapFineTuneButton(Offset offset) { if (_currWorkingItem?.feature != null) { HapticFeedback.lightImpact(); _currWorkingItem?.update(); int pointsNum = 0; pointsNum = _currWorkingItem?.feature!.innerPoints.length ?? 0; if (pointsNum > 0) { for (int i = 0; i < pointsNum; i++) { _currWorkingItem?.feature!.innerPoints[i] .addOffset(offset.dx, offset.dy); } } } } /// 开启长按定时器 void _startLongPressTimer(Offset offset) { /// 随着触发次数的增多,触发的距离越来越长 int fineTuneTimes = 0; _timer = Timer.periodic(const Duration(milliseconds: 50), (timer) { fineTuneTimes++; final scale = (1 + fineTuneTimes * 0.1).truncate().toDouble(); _onTapFineTuneButton(offset.scale(scale, scale)); }); } void _stopLongPressTimer() { if (_timer != null) { _timer!.cancel(); _timer = null; } } }