WinUI3中点击Lottie动画图标触发播放及MVVM绑定问题
WinUI3 Lottie动画图标MVVM解决方案
问题1:点击图标自身触发动画
将AnimatedVisualPlayer作为Button的Content,利用Button的点击区域覆盖图标,同时通过自定义Button样式去除默认边框、背景,让它看起来就是纯图标:
<Button Width="48" Height="48" Style="{StaticResource IconButtonStyle}"> <controls:AnimatedVisualPlayer x:Name="CreateFilePlayer" AutoPlay="False"> <lottie:LottieVisualSource Uri="ms-appx:///AnimatedVisuals/CreateFile.json" /> </controls:AnimatedVisualPlayer> </Button>
对应的IconButtonStyle示例:
<Style x:Key="IconButtonStyle" TargetType="Button"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Padding" Value="4"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}"/> </ControlTemplate> </Setter.Value> </Setter> </Style>
问题2:绑定ViewModel的Command
直接给包裹图标的Button绑定ViewModel中的CreateFileCommand,同时可以结合动画触发逻辑:
方案1:少量代码后置(仅处理动画播放)
XAML:
<Button Command="{x:Bind ViewModel.CreateFileCommand}" Click="AnimatedIconButton_Click" Width="48" Height="48" Style="{StaticResource IconButtonStyle}"> <controls:AnimatedVisualPlayer x:Name="CreateFilePlayer" AutoPlay="False"> <lottie:LottieVisualSource Uri="ms-appx:///AnimatedVisuals/CreateFile.json" /> </controls:AnimatedVisualPlayer> </Button>
代码后置(仅播放动画,无业务逻辑):
private async void AnimatedIconButton_Click(object sender, RoutedEventArgs e) { if ((sender as Button)?.Content is AnimatedVisualPlayer player) { await player.PlayAsync(fromProgress: 0, toProgress: 1, looped: false); } }
方案2:纯MVVM无代码后置
通过自定义附加属性,绑定ViewModel的状态属性来触发动画:
- 创建附加属性类:
public static class AnimatedPlayerTrigger { public static readonly DependencyProperty PlayAnimationProperty = DependencyProperty.RegisterAttached( "PlayAnimation", typeof(bool), typeof(AnimatedPlayerTrigger), new PropertyMetadata(false, OnPlayAnimationChanged)); public static bool GetPlayAnimation(DependencyObject obj) => (bool)obj.GetValue(PlayAnimationProperty); public static void SetPlayAnimation(DependencyObject obj, bool value) => obj.SetValue(PlayAnimationProperty, value); private static async void OnPlayAnimationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is AnimatedVisualPlayer player && (bool)e.NewValue) { await player.PlayAsync(0, 1, false); // 播放完成后重置状态,避免重复触发 SetPlayAnimation(player, false); } } }
- ViewModel中添加状态属性,在Command执行时触发:
private bool _isCreateFileAnimationPlaying; public bool IsCreateFileAnimationPlaying { get => _isCreateFileAnimationPlaying; set => SetProperty(ref _isCreateFileAnimationPlaying, value); } public ICommand CreateFileCommand => new RelayCommand(async () => { // 执行创建文件业务逻辑 await ExecuteCreateFile(); // 触发动画 IsCreateFileAnimationPlaying = true; });
- XAML中绑定附加属性:
<Button Command="{x:Bind ViewModel.CreateFileCommand}" Width="48" Height="48" Style="{StaticResource IconButtonStyle}"> <controls:AnimatedVisualPlayer local:AnimatedPlayerTrigger.PlayAnimation="{x:Bind ViewModel.IsCreateFileAnimationPlaying, Mode=TwoWay}" AutoPlay="False"> <lottie:LottieVisualSource Uri="ms-appx:///AnimatedVisuals/CreateFile.json" /> </controls:AnimatedVisualPlayer> </Button>
问题3:MVVM模式下触发动画(减少后置代码)
上面的纯MVVM方案已经实现了无代码后置的动画触发。如果需要在样式中复用,可以将附加属性整合到Button样式里:
<Style x:Key="AnimatedIconButtonStyle" TargetType="Button"> <Setter Property="Width" Value="48"/> <Setter Property="Height" Value="48"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <controls:AnimatedVisualPlayer local:AnimatedPlayerTrigger.PlayAnimation="{Binding PlayAnimation, RelativeSource={RelativeSource TemplatedParent}}" AutoPlay="False"> <lottie:LottieVisualSource Uri="{Binding AnimationUri, RelativeSource={RelativeSource TemplatedParent}}" /> </controls:AnimatedVisualPlayer> </ControlTemplate> </Setter.Value> </Setter> </Style>
使用时只需绑定Command和对应的ViewModel属性:
<Button Style="{StaticResource AnimatedIconButtonStyle}" Command="{x:Bind ViewModel.CreateFileCommand}" local:AnimatedPlayerTrigger.PlayAnimation="{x:Bind ViewModel.IsCreateFileAnimationPlaying, Mode=TwoWay}" Tag="ms-appx:///AnimatedVisuals/CreateFile.json" />
内容的提问来源于stack exchange,提问作者Mihai Socaciu
相关产品推荐
相关产品推荐

