infinitezero
infinitezero

Reputation: 2078

GradientStop Animation in Frame is not moving

I want to animate the gradient of the frame, so it appears to be ping-ponging from one end to the other. Sadly nothing moves but the rest behaves correctly:

  1. I can change the color of GradientStop
  2. The Frame disappears after IsLoading changes to false.

I checked via breakpoints that all parts of the code are executed. I did one more check and just setting the offset manually in the code behind also has no effect.

How can I get the Offset moving? I'm running this on a Pixel 5 - API 33 (Android 13.0) emulator builtin into VS 2022.

App.xaml

<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiMRE"
             x:Class="MauiMRE.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/Styles/Colors.xaml" />
                <ResourceDictionary Source="Resources/Styles/Styles.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

App.xaml.cs

namespace MauiMRE;

public partial class App : Application
{ 
    public App()
    {
        InitializeComponent();
        MainPage = new AppShell();
    }
}

AppShell.xaml

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MauiMRE.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiMRE"
    Shell.FlyoutBehavior="Disabled">

    <ShellContent
        Title="Home"
        ContentTemplate="{DataTemplate local:MainPage}"
        Route="MainPage" />

</Shell>

AppShell.xaml.cs

namespace MauiMRE;

public partial class AppShell : Shell
{
    public AppShell()
    {
        InitializeComponent();
    }
}

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiMRE.MainPage"             
             Title="Animation Example">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Frame IsVisible="{Binding IsLoading}" MinimumHeightRequest="40">
            <Frame.Background>
                <RadialGradientBrush Center="1.0,1.0">
                    <GradientStop Color="Gray" x:Name="GradientStop"
                    Offset="0.0" />
                    <GradientStop Color="White"
                    Offset="1.0" />
                </RadialGradientBrush>
            </Frame.Background>
        </Frame>
    </Grid>
</ContentPage>

MainPage.xaml.cs

namespace MauiMRE;

public partial class MainPage : ContentPage
{
    readonly MainPageVM mainPageVM;

    readonly Animation loadingAnimation;

    public MainPage(MainPageVM vm)
    {
        mainPageVM = vm;
        InitializeComponent();
        BindingContext = vm;

        loadingAnimation = new Animation(
          v => { GradientStop.Offset = (float)(1 - Math.Abs(v - 1)); }, 0, 2, Easing.Linear
          );
        GradientStop.Color = Microsoft.Maui.Graphics.Color.FromArgb("#0000ff"); // color changes
        GradientStop.Offset = 0.3f; // offset doesn't change
        vm.PropertyChanged += Vm_PropertyChanged;
    }

    protected override void OnAppearing()
    {
        mainPageVM.Load();
        base.OnAppearing();
    }

    private void Vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(mainPageVM.IsLoading))
        {
            var animationId = "loadingAnimation";
            if (mainPageVM.IsLoading)
            {
                loadingAnimation.Commit(this, animationId, 16, 1000, Easing.Linear, (v, c) => { GradientStop.Offset = 0; }, () => { return true; });
            }
            else
            {
                _ = this.AbortAnimation(animationId);
            }
        }
    }
}

MainPageVM.cs

using CommunityToolkit.Mvvm.ComponentModel;

namespace MauiMRE;


public partial class MainPageVM : ObservableObject
{    

    [ObservableProperty]
    private bool isLoading; 

    public MainPageVM()
    {

    }

    public async void Load()
    {
        IsLoading = true;
        await Task.Delay(8000);
        IsLoading = false;
    }
}

MauiProgram.cs

using Microsoft.Extensions.Logging;

namespace MauiMRE;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });

#if DEBUG
        builder.Logging.AddDebug();
#endif
        builder.Services.AddTransient<MainPage>();
        builder.Services.AddTransient<MainPageVM>();        
        return builder.Build();
    }
}

Upvotes: 0

Views: 76

Answers (2)

infinitezero
infinitezero

Reputation: 2078

I did some more experiments and even switched the Radiant gradient to a linear one. Interestingly, the offset property seems really broken. If you add more colours to it, it determines the order of the colours (by ordering them by offset), but that being said, the offsets (0.0, 0.1, 0.2, 0.3) will give the same gradient as (0.0, 0.25, 0.5, 0.75). Also, if you put the gradient along a diagonal (startpoint(0,0) endpoint(1,0)) the gradient doesn't care.

I looked into this example and they used a rectangle not a frame. I exchanged the Frame for a background and it works like a charm.

So the takeaway message is, gradients on a frame behave unexpectedly (at least to me).

Upvotes: 1

ToolmakerSteve
ToolmakerSteve

Reputation: 21213

Do you want the whole gradient to move? Animate Center.
Center.X, for left-to-right.

As seen in Radial Gradient doc,
Center="0.0,0.0" places center at upper-left.
Center="1.0,1.0" places center at lower-right.

————————————

Offset (despite its name) ranges from 0 to 1, as gradient is drawn from center to its radius. Doesn’t make sense for that to be animated from -1 to 1. However, from 0 to 1 should make the Center’s Color expand until the whole circle is that color. If it has NO effect on color, that might be a bug.

Given a second GradientStop at Offset 1.0:

  • First GradientStop with Offset 0.3 means inner 30% of circle is solid color, then the gradient starts.
  • Try Offset 0.9, for a dramatic difference. Most of the circle becomes solid color. (Unless you add a third GradientStop at 0, to start from a different center color.)

Upvotes: 0

Related Questions