功能更新

This commit is contained in:
GG Z
2026-02-12 21:29:00 +08:00
parent a9faf251be
commit b3479d1f39
342 changed files with 4671 additions and 2223 deletions

View File

@@ -0,0 +1,119 @@
using System.Windows.Media.Animation;
using System.Windows.Threading;
namespace Melskin.Controls;
/// <summary>
/// 代表一个通知视图用于在应用程序中显示系统通知。此类继承自Window并根据提供的Notification模型和位置信息来初始化自身。支持抽屉式滑入和滑出动画效果。
/// </summary>
public partial class NotificationView
{
private readonly DispatcherTimer? closeTimer;
private readonly NotificationPlacement placement; // 新增一个字段来存储位置
/// <summary>
/// 当通知视图加载完毕并准备好显示时触发的事件。此事件允许外部代码在通知视图完全初始化后执行特定操作,例如调整其位置或开始动画。
/// </summary>
public event Action<NotificationView>? Ready;
/// <summary>
/// 获取与此视图关联的通知模型。该模型包含了通知的标题、消息内容、类型以及显示时长等信息。
/// </summary>
public NotificationModel Model { get; }
/// <summary>
/// 代表一个通知视图用于在应用程序中显示系统通知。该类继承自Window并根据提供的Notification模型和位置信息来初始化自身。
/// </summary>
public NotificationView(NotificationModel model, NotificationPlacement placement) // 构造函数接收placement
{
InitializeComponent();
this.Model = model;
this.DataContext = this.Model;
this.placement = placement; // 保存placement
this.Opacity = 0; // 初始时依然保持透明,防止在动画开始前闪烁
this.Loaded += (_, _) => Ready?.Invoke(this);
if (model.Duration <= TimeSpan.Zero) return;
closeTimer = new DispatcherTimer { Interval = model.Duration };
closeTimer.Tick += (_, _) => AnimateOut();
}
/// <summary>
/// 命令视图执行抽屉式滑入动画
/// </summary>
public void AnimateIn(double finalLeft, double finalTop)
{
// Manager已经计算好了最终位置我们只需执行动画
this.Top = finalTop; // Y坐标直接设定
// 根据位置判断是从左侧滑入还是右侧滑入
var isRightSide = placement == NotificationPlacement.TopRight ||
placement == NotificationPlacement.BottomRight;
var startLeft = isRightSide
? finalLeft + this.ActualWidth + 10 // 从右侧屏幕外开始
: finalLeft - this.ActualWidth - 10; // 从左侧屏幕外开始
// 在动画开始前,立即将窗口移动到屏幕外的起始位置
this.Left = startLeft;
// 创建滑入动画
var slideAnim = new DoubleAnimation(startLeft, finalLeft, TimeSpan.FromMilliseconds(400))
{
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
};
// 同时,让窗口从透明变为不透明,这是一个很好的辅助效果
var fadeAnim = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(200));
// 应用动画
this.BeginAnimation(Window.LeftProperty, slideAnim);
this.BeginAnimation(Window.OpacityProperty, fadeAnim);
closeTimer?.Start();
}
/// <summary>
/// 命令视图执行抽屉式滑出动画
/// </summary>
public void AnimateOut()
{
closeTimer?.Stop();
// 计算滑出到屏幕外的目标位置
var isRightSide = placement is NotificationPlacement.TopRight or NotificationPlacement.BottomRight;
var endLeft = isRightSide ? this.Left + this.ActualWidth + 10 : this.Left - this.ActualWidth - 10;
// 创建滑出动画
var slideAnim = new DoubleAnimation(this.Left, endLeft, TimeSpan.FromMilliseconds(300))
{
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }
};
// 同时淡出
var fadeAnim = new DoubleAnimation(this.Opacity, 0, TimeSpan.FromMilliseconds(250));
// 当动画完成时,关闭窗口
slideAnim.Completed += (_, _) => this.Close();
this.BeginAnimation(Window.LeftProperty, slideAnim);
this.BeginAnimation(Window.OpacityProperty, fadeAnim);
}
/// <summary>
/// 当其他通知关闭时,平滑地移动到新位置 (这个方法保持不变)
/// </summary>
public void AnimateMove(double newTop)
{
var moveAnim = new DoubleAnimation(this.Top, newTop, TimeSpan.FromMilliseconds(350))
{
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
};
this.BeginAnimation(Window.TopProperty, moveAnim);
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
AnimateOut();
}
}