uwplottiewindows-themes

Change animation theme when system theme is changing in UWP using Lottie


I have a .gif icon which I am trying to set using Lottie in UWP. The icon has two versions for light and dark mode respectively. But I cant change the icon when application theme is changed. I have followed this way,

  1. Created a theme dictionary using this,

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
                    xmlns:lottie="using:Microsoft.Toolkit.Uwp.UI.Lottie">
    <ResourceDictionary>    
        <ResourceDictionary.ThemeDictionaries>
            <ResourceDictionary x:Key="Light">
                 <Style x:Key="AnimationStyle" TargetType="lottie:LottieVisualSource">
                    <Setter Property="UriSource" Value="/Assets/Icons/theme-light/lottie_animation.json" />
                 </Style>
            </ResourceDictionary>
            <ResourceDictionary x:Key="Dark">
               <Style x:Key="AnimationStyle" TargetType="lottie:LottieVisualSource">
                   <Setter Property="UriSource" Value="/Assets/Icons/theme-dark/lottie_animation.json" />
               </Style>
            </ResourceDictionary>
    </ResourceDictionary.ThemeDictionaries>
    </ResourceDictionary>   
    
  2. After that I have called it following this,

    <Grid.Row="3">
        <muxc:AnimatedVisualPlayer HorizontalAlignment="Center"
                               VerticalAlignment="Center"
                               Stretch="Uniform">
            <lottie:LottieVisualSource UriSource="{ThemeResource AnimationStyle}"/>
        </muxc:AnimatedVisualPlayer>
    </Grid>

But it does not show in both theme (Dark and Light). Please help :(


Solution

  • First of all, you could just save the string value for the UriSource. Then I tested this, the result shows that the LottieVisualSource will not use the updated source when the Theme is changed. So we need to use the Theme Listener to detect the theme change and manually update the UriSource.

    Here is the code that I'm using for testing.

     <ResourceDictionary.ThemeDictionaries>
        <ResourceDictionary x:Key="Light">
            <x:String x:Key="AnimationStyle">ms-appx:///Assets/Icon/Theme-Light/First.json</x:String>
        </ResourceDictionary>
        <ResourceDictionary x:Key="Dark">
            <x:String x:Key="AnimationStyle">ms-appx:///Assets/Icon/Theme-Dark/Second.json</x:String>
        </ResourceDictionary>
        <ResourceDictionary x:Key="HighContrast">
            
        </ResourceDictionary>
    </ResourceDictionary.ThemeDictionaries>
    

    MainPage.Xaml

        <Page.Resources>
        <!--for a simple test, add the dictionary in the page resource-->
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="re.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
    
        <TextBlock Grid.Row="0" Text="{ThemeResource AnimationStyle}"/>
    
        <muxc:AnimatedVisualPlayer Grid.Row="1" x:Name="LottiePlayer" AutoPlay="True" >
            <lottie:LottieVisualSource x:Name="LottieJsonSource" Options="All" UriSource="{ThemeResource AnimationStyle}"/>
        </muxc:AnimatedVisualPlayer>
    </Grid>
    

    MainPage.Xaml.cs

        public MainPage()
        {
            this.InitializeComponent();
    
            var Listener = new ThemeListener();
            Listener.ThemeChanged += Listener_ThemeChanged;
        }
    
        private void Listener_ThemeChanged(ThemeListener sender)
        {
            Debug.WriteLine("ThemeChanged");
            //update the source manually. The AnimationStyle is actually changed when the theme is changed
            //but the LottieJsonSource is still using the old cache.
            LottieJsonSource.UriSource = new Uri((string)this.Resources["AnimationStyle"]); ;
        }