popup_layer.dart 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import 'dart:math';
  2. import 'package:calendar_view/calendar_page/month_calendar/more_schedule_popup.dart';
  3. import 'package:calendar_view/popup_layer/popup_layer_controller.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:get/get.dart';
  6. class PopupLayer extends StatefulWidget {
  7. const PopupLayer({super.key});
  8. @override
  9. State<PopupLayer> createState() => _PopupLayerState();
  10. }
  11. class _PopupLayerState extends State<PopupLayer> {
  12. PopupLayerController popupLayerController = Get.find<PopupLayerController>();
  13. bool _isShowPopup = false;
  14. GlobalKey moreSchedulePopupKey = GlobalKey();
  15. @override
  16. void initState() {
  17. super.initState();
  18. popupLayerController.onPopupMoreSchedule.addListener(_onPopupMoreSchedule);
  19. }
  20. @override
  21. void dispose() {
  22. super.dispose();
  23. popupLayerController.onPopupMoreSchedule
  24. .removeListener(_onPopupMoreSchedule);
  25. }
  26. /// 收到显示更多日程的事件
  27. void _onPopupMoreSchedule(e, GlobalKey key) {
  28. setState(() {
  29. _isShowPopup = true;
  30. moreSchedulePopupKey = key;
  31. });
  32. }
  33. @override
  34. Widget build(BuildContext context) {
  35. return _isShowPopup
  36. ? Listener(
  37. behavior: HitTestBehavior.translucent,
  38. onPointerUp: (event) {
  39. setState(() {
  40. _isShowPopup = false;
  41. });
  42. },
  43. child: _buildMoreSchedulePopup(moreSchedulePopupKey),
  44. )
  45. : Container();
  46. }
  47. /// 只做容器而无需负责内容
  48. /// [trigger] 触发器的 key
  49. Widget _buildMoreSchedulePopup(GlobalKey trigger) {
  50. final Size triggerSize = getWidgetSize(trigger);
  51. final Offset triggerOffset = getWidgetOffset(trigger);
  52. return Flow(
  53. delegate: AutoAlignFlowDelegate(triggerOffset),
  54. children: [
  55. Container(
  56. decoration: BoxDecoration(
  57. color: Colors.white,
  58. borderRadius: BorderRadius.circular(8),
  59. border: Border.all(color: Colors.black12, width: 1),
  60. boxShadow: const [
  61. BoxShadow(
  62. color: Colors.black12,
  63. offset: Offset(3, 3),
  64. blurRadius: 25,
  65. ),
  66. ],
  67. ),
  68. width: max(triggerSize.width, 220),
  69. child: MoreSchedulePopup(
  70. scheduleData: popupLayerController.currMoreScheduleData,
  71. ),
  72. ),
  73. ],
  74. );
  75. }
  76. static const double _popupLayerMarginTop = 70;
  77. static const double _popupLayerMarginLeft = 240;
  78. /// 通过组件的 key 获取对应的组件的大小信息
  79. /// [key] 组件的 key
  80. Size getWidgetSize(GlobalKey key) {
  81. try {
  82. final RenderBox renderBox =
  83. key.currentContext?.findRenderObject() as RenderBox;
  84. return renderBox.size;
  85. } catch (e) {
  86. print('获取大小信息失败: $e');
  87. return Size.zero;
  88. }
  89. }
  90. /// 通过组件的 key 获取对应的组件在弹出层的位置
  91. /// [key] 组件的 key
  92. Offset getWidgetOffset(GlobalKey key) {
  93. try {
  94. final RenderBox renderBox =
  95. key.currentContext?.findRenderObject() as RenderBox;
  96. return renderBox
  97. .localToGlobal(Offset.zero)
  98. .translate(-_popupLayerMarginLeft, -_popupLayerMarginTop);
  99. } catch (e) {
  100. print('获取位置信息失败: $e');
  101. return Offset.zero;
  102. }
  103. }
  104. }
  105. /// 自动对齐委托
  106. class AutoAlignFlowDelegate extends FlowDelegate {
  107. final Offset triggerOffset;
  108. AutoAlignFlowDelegate(this.triggerOffset);
  109. @override
  110. void paintChildren(FlowPaintingContext context) {
  111. final Size containerSize = context.size;
  112. for (int i = 0; i < context.childCount; i++) {
  113. final Size childSize = context.getChildSize(i) ?? Size.zero;
  114. double x = triggerOffset.dx;
  115. double y = triggerOffset.dy;
  116. if (containerSize.height - y < childSize.height) {
  117. y = containerSize.height - childSize.height;
  118. }
  119. if (containerSize.width - x < childSize.width) {
  120. x = containerSize.width - childSize.width;
  121. }
  122. context.paintChild(i, transform: Matrix4.translationValues(x, y, 0));
  123. }
  124. }
  125. @override
  126. bool shouldRepaint(FlowDelegate oldDelegate) {
  127. return oldDelegate != this;
  128. }
  129. }