import 'package:fis_measure/interfaces/date_types/int_size.dart'; import 'package:fis_measure/interfaces/process/player/play_controller.dart'; import 'package:fis_measure/interfaces/process/workspace/application.dart'; import 'package:fis_measure/view/paint/ai_patint_controller.dart'; import 'package:fis_measure/view/paint/parts/dash_line.dart'; import 'package:fis_measure/view/paint/parts/dots.dart'; import 'package:fis_measure/view/paint/parts/rectangle.dart'; import 'package:fis_measure/view/player/controller.dart'; import 'package:fis_measure/view/player/enums.dart'; import 'package:fis_measure/view/player/events.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; class AIPaintInfo extends StatefulWidget { /// 播放器控制器 final VidPlayerController controller; final double? width; final double? height; const AIPaintInfo( this.controller, { Key? key, this.width, this.height, }) : super(key: key); @override State createState() => _AIPaintInfoState(); } class _AIPaintInfoState extends State { late final aiPatintController = Get.put( AiPatintController( widget.controller, ), ); late bool ifShowAiResult; /// 播放控制器 final playerController = Get.find(); @override void initState() { //监听Widget是否绘制完毕 super.initState(); widget.controller.eventHandler.addListener(onControllerEvent); } @override void dispose() { super.dispose(); widget.controller.eventHandler.removeListener(onControllerEvent); // _removeListenrs(); } void onControllerEvent(Object sender, VidPlayerEvent e) { if (e is VidPlayerStatusChangeEvent) { updateFrame(); aiPatintController.state.vidStatus = e.status; } if (e is VidPlayerFrameIndexChangeEvent) { onFrameChanged(e); } if (e is VidPlayerBrightnessChangeEvent) { updateFrame(); } if (e is VidPlayerContrastChangeEvent) { updateFrame(); } } void onFrameChanged(VidPlayerFrameIndexChangeEvent e) { setState(() { aiPatintController.state.frameIndex = e.index; }); } void updateFrame() { setState(() {}); } @override void didUpdateWidget(covariant AIPaintInfo oldWidget) { if (oldWidget.controller != widget.controller) { throw UnsupportedError("[VidTestPlayer] unsupport replace controller."); } super.didUpdateWidget(oldWidget); } @override Widget build(BuildContext context) { return Obx( () { Widget? child; switch (aiPatintController.state.vidStatus) { case VidPlayStatus.init: child = Container(); break; case VidPlayStatus.ready: child = Container(); break; case VidPlayStatus.loadFail: child = Container(); break; case VidPlayStatus.play: child = LayoutBuilder(builder: (context, constraints) { try { ifShowAiResult = aiPatintController.onGetAIResultsInfo(); } catch (e) { ifShowAiResult = true; } if (!ifShowAiResult) { return const SizedBox(); } else { return CustomMultiChildLayout( delegate: _LayerLayoutDelegate(), children: [ LayoutId( id: _LayerLayoutIds.rectangle, child: CustomPaint( painter: PaintAIRectangle( aiPatintController.left, aiPatintController.top, aiPatintController.width, aiPatintController.height, ), ), ) ], ); } }); break; case VidPlayStatus.pause: child = LayoutBuilder(builder: (context, constraints) { if (!aiPatintController.onGetAIResultsInfo()) { return const SizedBox(); } else { return CustomMultiChildLayout( delegate: _LayerLayoutDelegate(), children: [ LayoutId( id: _LayerLayoutIds.dots, child: Stack( children: aiPatintController.aiDotsResultsList .map( (e) => Obx( () { return CustomPaint( painter: PaintAIDots( e, aiPatintController.state.aiResultIndex, ), ); }, ), ) .toList(), ), ), LayoutId( id: _LayerLayoutIds.dashLine, child: Stack( children: aiPatintController.aiDotsResultsList .map( (e) => CustomPaint( painter: PaintAIDashLine( e, ), ), ) .toList(), ), ), ], ); } }); break; case VidPlayStatus.stop: case VidPlayStatus.dispose: child = Container(child: const Text("Closed")); break; } return buildBox(context, child); }, ); } Widget buildBox(BuildContext context, Widget child) { if (aiPatintController.state.ifShowAi) { return Container( alignment: Alignment.center, child: child, ); } else { return const SizedBox(); } } } class _LayerLayoutDelegate extends MultiChildLayoutDelegate { Offset? layoutOffset; Size? layoutSize; _LayerLayoutDelegate(); @override void performLayout(Size size) { final application = Get.find(); final vidFrame = application.frameData; final imageSize = IntSize.fill(vidFrame?.width ?? 0, vidFrame?.height ?? 0); /// 以Contain方式填充布局,计算定位偏移量 calcSize(size, imageSize); final offset = layoutOffset!; final renderSize = layoutSize!; /// 同步图像显示尺寸 application.displaySize = renderSize; /// 其他层按播放器尺寸位置层叠布局 layoutLayer(_LayerLayoutIds.dots, offset, renderSize); layoutLayer(_LayerLayoutIds.dashLine, offset, renderSize); layoutLayer(_LayerLayoutIds.rectangle, offset, renderSize); layoutLayer(_LayerLayoutIds.aiResult, offset, renderSize); } void layoutLayer(_LayerLayoutIds layoutId, Offset offset, Size size) { if (hasChild(layoutId)) { layoutChild( layoutId, BoxConstraints.loose(size), ); positionChild(layoutId, offset); } } void calcSize(Size size, IntSize imageSize) { final parentWHRatio = size.width / size.height; final imageWHRatio = imageSize.width / imageSize.height; if (imageWHRatio < parentWHRatio) { // 高度撑满 final layoutWidth = size.height * imageWHRatio; final layoutHeight = size.height; final offsetX = (size.width - layoutWidth) / 2; layoutOffset = Offset(offsetX, 0); layoutSize = Size(layoutWidth, layoutHeight); } else if (imageWHRatio > parentWHRatio) { // 宽度撑满 final layoutWidth = size.width; final layoutHeight = size.width / imageWHRatio; final offsetY = (size.height - layoutHeight) / 2; layoutOffset = Offset(0, offsetY); layoutSize = Size(layoutWidth, layoutHeight); } else { layoutOffset = Offset.zero; layoutSize = size; } } @override bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) { return false; } } enum _LayerLayoutIds { /// 点 dots, /// 虚线 dashLine, /// 矩形 rectangle, /// ai结果 aiResult }