You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

190 lines
6.3 KiB

using ReactiveUI.Avalonia;
using Avalonia.Markup.Xaml;
using AuroraDesk.Presentation.ViewModels.Pages;
using ReactiveUI;
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Threading;
using Avalonia.Skia.Lottie;
using Avalonia.VisualTree;
using Avalonia.Interactivity;
namespace AuroraDesk.Presentation.Views.Pages;
public partial class BreathePageView : ReactiveUserControl<BreathePageViewModel>
{
private Lottie? _lottieControl;
private ContentControl? _lottieContainer;
private bool _isDisposed;
private IDisposable? _repeatCountSubscription;
public BreathePageView()
{
InitializeComponent();
this.WhenActivated(disposables =>
{
// 重置停用标志
_isDisposed = false;
// 查找容器控件
_lottieContainer = this.FindControl<ContentControl>("LottieContainer");
if (_lottieContainer == null || ViewModel == null)
{
return;
}
// 创建新的 Lottie 控件实例
CreateLottieControl(disposables);
// 订阅动画路径变化
var pathSubscription = ViewModel
.WhenAnyValue(x => x.AnimationPath)
.Where(path => !string.IsNullOrEmpty(path))
.DistinctUntilChanged()
.ObserveOn(AvaloniaScheduler.Instance)
.Subscribe(path =>
{
if (_isDisposed || _lottieControl == null)
{
return;
}
try
{
Dispatcher.UIThread.Post(() =>
{
if (!_isDisposed && _lottieControl != null && !string.IsNullOrEmpty(path))
{
try
{
_lottieControl.Path = path;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[BreathePageView] Failed to set animation path: {ex.GetType().Name} - {ex.Message}");
}
}
}, DispatcherPriority.Normal);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[BreathePageView] Failed to update animation path: {ex.GetType().Name} - {ex.Message}");
}
});
disposables.Add(pathSubscription);
// 页面停用时的清理
disposables.Add(Disposable.Create(() =>
{
_isDisposed = true;
_repeatCountSubscription?.Dispose();
_repeatCountSubscription = null;
DestroyLottieControl();
}));
});
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void CreateLottieControl(CompositeDisposable disposables)
{
if (_lottieContainer == null || ViewModel == null || _isDisposed)
{
return;
}
try
{
// 获取 baseUri(用于资源加载)
// 使用程序集资源的基础 URI
var baseUri = new Uri("avares://AuroraDesk.Presentation/");
// 创建新的 Lottie 控件实例
_lottieControl = new Lottie(baseUri)
{
RepeatCount = ViewModel.RepeatCount,
Stretch = Avalonia.Media.Stretch.Uniform,
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
ClipToBounds = false
};
// 设置初始路径
if (!string.IsNullOrEmpty(ViewModel.AnimationPath))
{
_lottieControl.Path = ViewModel.AnimationPath;
}
// 订阅 RepeatCount 变化
if (ViewModel != null)
{
_repeatCountSubscription = ViewModel.WhenAnyValue(x => x.RepeatCount)
.Subscribe(count =>
{
if (_lottieControl != null && !_isDisposed)
{
Dispatcher.UIThread.Post(() =>
{
if (_lottieControl != null && !_isDisposed)
{
_lottieControl.RepeatCount = count;
}
});
}
});
if (_repeatCountSubscription != null)
{
disposables.Add(_repeatCountSubscription);
}
}
// 将控件添加到容器
_lottieContainer.Content = _lottieControl;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[BreathePageView] Failed to create Lottie control: {ex.GetType().Name} - {ex.Message}");
}
}
private void DestroyLottieControl()
{
try
{
if (_lottieContainer != null)
{
// 清空容器内容,这会触发 Lottie 控件的卸载和资源清理
Dispatcher.UIThread.Post(() =>
{
try
{
if (_lottieContainer != null)
{
_lottieContainer.Content = null;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[BreathePageView] Failed to clear container: {ex.GetType().Name} - {ex.Message}");
}
}, DispatcherPriority.Normal);
}
_lottieControl = null;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[BreathePageView] Failed to destroy Lottie control: {ex.GetType().Name} - {ex.Message}");
}
}
}