floating_window.dart 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import 'package:flutter/material.dart';
  2. import 'package:vnoteapp/components/floating_window/click_notification.dart';
  3. import 'package:vnoteapp/components/floating_window/floating_button.dart';
  4. import 'package:vnoteapp/components/floating_window/floating_item.dart';
  5. import 'package:vnoteapp/components/floating_window/floating_items.dart';
  6. import 'package:vnoteapp/components/floating_window/floating_window_model.dart';
  7. import 'package:vnoteapp/components/floating_window/floating_window_shared_data_widget.dart';
  8. /// [FloatingWindow] 悬浮窗
  9. class FloatingWindow extends StatefulWidget {
  10. const FloatingWindow({super.key});
  11. @override
  12. _FloatingWindowState createState() => _FloatingWindowState();
  13. }
  14. class _FloatingWindowState extends State<FloatingWindow> {
  15. List<Map<String, String>> ls = [
  16. {'title': "测试一下", "imageUrl": "assets/images/no_data.png"},
  17. ];
  18. /// 悬浮窗共享数据
  19. FloatingWindowModel? windowModel;
  20. /// [isEntering] 列表项是否拥有进场动画
  21. bool isEntering = true;
  22. @override
  23. void initState() {
  24. super.initState();
  25. windowModel = FloatingWindowModel(dataList: ls, isLeft: true);
  26. isEntering = true;
  27. }
  28. @override
  29. Widget build(BuildContext context) {
  30. return FloatingWindowSharedDataWidget(
  31. data: windowModel!,
  32. child: windowModel!.isEmpty
  33. ? Container()
  34. : Stack(
  35. fit: StackFit.expand,
  36. children: [
  37. /// 列表项遮盖层,增加淡化切换动画
  38. AnimatedSwitcher(
  39. duration: const Duration(milliseconds: 100),
  40. child: windowModel!.isButton
  41. ? Container()
  42. : GestureDetector(
  43. onTap: () {
  44. FloatingItem.reverse();
  45. Future.delayed(const Duration(milliseconds: 110),
  46. () {
  47. setState(() {
  48. windowModel!.isButton = true;
  49. });
  50. });
  51. },
  52. child: Container(
  53. decoration: const BoxDecoration(
  54. color: Color.fromRGBO(0xEF, 0xEF, 0xEF, 0.9)),
  55. ),
  56. ),
  57. ),
  58. NotificationListener<ClickNotification>(
  59. onNotification: (notification) {
  60. /// 列表项关闭事件
  61. if (notification.deletedIndex != -1) {
  62. windowModel?.deleteIndex = notification.deletedIndex;
  63. setState(() {
  64. FloatingItem.resetList();
  65. windowModel?.dataList
  66. .removeAt(notification.deletedIndex);
  67. isEntering = false;
  68. });
  69. }
  70. /// 列表点击事件
  71. if (notification.clickIndex != -1) {
  72. print(notification.clickIndex);
  73. }
  74. /// 悬浮按钮点击Widget改变事件
  75. if (notification.changeWidget) {
  76. setState(() {
  77. /// 释放列表进出场动画资源
  78. FloatingItem.resetList();
  79. windowModel?.isButton = false;
  80. isEntering = true;
  81. });
  82. }
  83. return false;
  84. },
  85. child: windowModel!.isButton
  86. ? const FloatingButton()
  87. : FloatingItems(
  88. isEntering: isEntering,
  89. ),
  90. )
  91. ],
  92. ),
  93. );
  94. }
  95. }