|
@@ -0,0 +1,127 @@
|
|
|
+import 'package:calendar_view/notification_demo/notification_card.dart';
|
|
|
+import 'package:calendar_view/notification_demo/notification_controller.dart';
|
|
|
+import 'package:flutter/material.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
+
|
|
|
+/// 全局消息通知层
|
|
|
+class GlobalNotificationLayer extends StatefulWidget {
|
|
|
+ const GlobalNotificationLayer({Key? key, required this.child})
|
|
|
+ : super(key: key);
|
|
|
+ final Widget child;
|
|
|
+
|
|
|
+ @override
|
|
|
+ GlobalNotificationLayerState createState() => GlobalNotificationLayerState();
|
|
|
+}
|
|
|
+
|
|
|
+class GlobalNotificationLayerState extends State<GlobalNotificationLayer> {
|
|
|
+ late NotificationController notificationController;
|
|
|
+ List<SystemNotification> notifications = [];
|
|
|
+ final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
|
|
|
+ final ScrollController _scrollController = ScrollController();
|
|
|
+
|
|
|
+ static final double _notificationWidth = 420;
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ super.initState();
|
|
|
+ notificationController =
|
|
|
+ Get.put<NotificationController>(NotificationController());
|
|
|
+ notificationController.onReceiveNotification
|
|
|
+ .addListener(_onReceiveNotification);
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ super.dispose();
|
|
|
+ notificationController.onReceiveNotification
|
|
|
+ .removeListener(_onReceiveNotification);
|
|
|
+ }
|
|
|
+
|
|
|
+ void _onReceiveNotification(e, SystemNotification notification) {
|
|
|
+ _insertNotification(notifications.length, notification);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新增消息
|
|
|
+ void _insertNotification(index, SystemNotification item) {
|
|
|
+ if (_listKey.currentState is! AnimatedListState) return;
|
|
|
+ notifications.insert(index, item);
|
|
|
+ _listKey.currentState!.insertItem(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ void _removeNotification(index) {
|
|
|
+ if (_listKey.currentState is! AnimatedListState) return;
|
|
|
+ _listKey.currentState!.removeItem(
|
|
|
+ index,
|
|
|
+ (context, animation) =>
|
|
|
+ _buildNotificationSizeOut(context, index, animation),
|
|
|
+ duration: const Duration(milliseconds: 120));
|
|
|
+
|
|
|
+ /// 延迟删除,避免动画过程中被重复删除
|
|
|
+ Future.delayed(const Duration(milliseconds: 120), () {
|
|
|
+ notifications.removeAt(index);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return Stack(
|
|
|
+ children: [
|
|
|
+ widget.child,
|
|
|
+ Positioned(
|
|
|
+ bottom: 0,
|
|
|
+ right: 0,
|
|
|
+ child: SizedBox(
|
|
|
+ width: _notificationWidth,
|
|
|
+ child: Align(
|
|
|
+ alignment: Alignment.bottomRight,
|
|
|
+ child: AnimatedList(
|
|
|
+ key: _listKey,
|
|
|
+ initialItemCount: notifications.length,
|
|
|
+ controller: _scrollController,
|
|
|
+ shrinkWrap: true,
|
|
|
+ itemBuilder: _buildNotificationFromRightSliderIn,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 从右侧划入
|
|
|
+ Widget _buildNotificationFromRightSliderIn(
|
|
|
+ BuildContext context, int index, Animation<double> animation) {
|
|
|
+ return SlideTransition(
|
|
|
+ position: Tween<Offset>(
|
|
|
+ begin: const Offset(1, 0),
|
|
|
+ end: Offset.zero,
|
|
|
+ ).animate(CurvedAnimation(
|
|
|
+ parent: animation,
|
|
|
+ curve: Curves.fastOutSlowIn,
|
|
|
+ reverseCurve: Curves.fastOutSlowIn.flipped)),
|
|
|
+ child: SizeTransition(
|
|
|
+ axis: Axis.vertical,
|
|
|
+ sizeFactor: animation,
|
|
|
+ child: _buildNotificationCard(index),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 收缩移除
|
|
|
+ Widget _buildNotificationSizeOut(
|
|
|
+ BuildContext context, int index, Animation<double> animation) {
|
|
|
+ return SizeTransition(
|
|
|
+ axis: Axis.vertical,
|
|
|
+ sizeFactor: animation,
|
|
|
+ child: _buildNotificationCard(index),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildNotificationCard(int index) {
|
|
|
+ return NotificationCard(
|
|
|
+ notification: notifications[index],
|
|
|
+ onClose: () {
|
|
|
+ _removeNotification(index);
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|