Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KeyFrame animation whose last animated value has Cue < 1.0 doesn't hold value #11801

Closed
billhenn opened this issue Jun 15, 2023 · 1 comment · Fixed by #13775
Closed

KeyFrame animation whose last animated value has Cue < 1.0 doesn't hold value #11801

billhenn opened this issue Jun 15, 2023 · 1 comment · Fixed by #13775

Comments

@billhenn
Copy link
Contributor

When running a KeyFrame animation with FillMode = Forward, the last value that was animated in the animation should be what "holds" when the animation completes. This currently works but ONLY if the last value was set at Cue = 1.0. If the last value was set at any value before that, such as Cue = 0.5, it will not be held after the animation completes.

Avalonia Repro

This sample has 3 rectangles. Red is always visible, while Green and Blue animate to be visible when the button is clicked. When the animation runs, Green fades in and back out, and Blue fades in and remains visible. Green sets the Cue = 0.5 and Blue sets the Cue = 1.0.

image

<Grid ColumnDefinitions="100,100,100" Height="100">
	<Rectangle x:Name="redRectangle" Fill="Red" />
	<Rectangle x:Name="greenRectangle" Grid.Column="1" Fill="Green" Opacity="0" />
	<Rectangle x:Name="blueRectangle" Grid.Column="2" Fill="Blue" Opacity="0" />
</Grid>
<TextBlock TextWrapping="Wrap">Red shape is always visible. Green shape animates Opacity property with Cue=0.5, Blue shape animates Opacity property with Cue=1.0.  Only the Red and Blue shapes remain visible after clicking the button, which is inconsistent with WPF.</TextBlock>
<ToggleButton x:Name="cueAnimationToggleButton" Content="Toggle this button to try and show the green and blue shapes" Click="OnTestCueAnimationButtonClick" />
private CancellationTokenSource? _cancellationTokenSource;

private async void OnTestCueAnimationButtonClick(object? sender, RoutedEventArgs e) {
	var opacityAnim = new Animation() {
		Duration = TimeSpan.FromSeconds(1),
		FillMode = FillMode.Forward,
	};

	var opacityNotAtEndAnim = new Animation() {
		Duration = TimeSpan.FromSeconds(1),
		FillMode = FillMode.Forward,
	};

	if (cueAnimationToggleButton.IsChecked == true) {
		opacityNotAtEndAnim.Children.Add(
			new KeyFrame() {
				Cue = new Cue(0.5),
				Setters = {
					new Setter(OpacityProperty, 1.0)
				}
			}
		);

		opacityAnim.Children.Add(
			new KeyFrame() {
				Cue = new Cue(1.0),
				Setters = {
					new Setter(OpacityProperty, 1.0)
				}
			}
		);
	}
	else {
		opacityNotAtEndAnim.Children.Add(
			new KeyFrame() {
				Cue = new Cue(1.0),
				Setters = {
					new Setter(OpacityProperty, 0.0)
				}
			}
		);

		opacityAnim.Children.Add(
			new KeyFrame() {
				Cue = new Cue(1.0),
				Setters = {
					new Setter(OpacityProperty, 0.0)
				}
			}
		);
	}
			
	_cancellationTokenSource?.Cancel();
			
	_cancellationTokenSource = new CancellationTokenSource();
	var token = _cancellationTokenSource.Token;

	await opacityNotAtEndAnim.RunAsync(greenRectangle, token);
	await opacityAnim.RunAsync(blueRectangle, token);

}

WPF Comparison

WPF properly holds the last value animated, regardless of which cue time it had. Here is a simple sample with effectively the same code as above, but for WPF:

image
Note that after clicking the button, all three shapes remain visible.

<StackPanel>
    <TextBlock Text="❌ Boolean animation doesn't hold end" />
    <Grid Height="100">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <Rectangle x:Name="redRectangle" Fill="Red" />
        <Rectangle x:Name="greenRectangle" Grid.Column="1" Fill="Green" Opacity="0" />
        <Rectangle x:Name="blueRectangle" Grid.Column="2" Fill="Blue" Opacity="0" />
    </Grid>
    <ToggleButton x:Name="cueAnimationToggleButton" Content="Toggle this button to try and show the green and blue shapes" Click="OnTestCueAnimationButtonClick" />
</StackPanel>
private void OnTestCueAnimationButtonClick(object? sender, RoutedEventArgs e) {
	var opacityAnim = new DoubleAnimationUsingKeyFrames() {
		Duration = TimeSpan.FromSeconds(1),
	};

	var opacityNotAtEndAnim = new DoubleAnimationUsingKeyFrames() {
		Duration = TimeSpan.FromSeconds(1),
    };

	if (cueAnimationToggleButton.IsChecked == true) {
		opacityNotAtEndAnim.KeyFrames.Add(
			new LinearDoubleKeyFrame(1.0) {
				KeyTime = KeyTime.FromPercent(0.5),
			}
		);

		opacityAnim.KeyFrames.Add(
			new LinearDoubleKeyFrame(1.0) {
				KeyTime = KeyTime.FromPercent(1.0),
			}
		);
	}
	else {
		opacityNotAtEndAnim.KeyFrames.Add(
			new LinearDoubleKeyFrame(0.0) {
				KeyTime = KeyTime.FromPercent(1.0),
			}
		);

		opacityAnim.KeyFrames.Add(
			new LinearDoubleKeyFrame(0.0) {
				KeyTime = KeyTime.FromPercent(1.0),
			}
		);
	}

	Storyboard.SetTargetProperty(opacityNotAtEndAnim, new PropertyPath(OpacityProperty));
	var sb1 = new Storyboard();
	sb1.Children.Add(opacityNotAtEndAnim);
	sb1.Begin(greenRectangle);
			
	Storyboard.SetTargetProperty(opacityAnim, new PropertyPath(OpacityProperty));
	var sb2 = new Storyboard();
	sb2.Children.Add(opacityAnim);
	sb2.Begin(blueRectangle);
}
@MrJul
Copy link
Member

MrJul commented Nov 22, 2023

While fixing some warnings across the solution, I came across the test AnimationIterationTests.Check_FillMode_End_Value, which has an warning coming from the xUnit analyzer because the tests parameters are unused.

Indeed, using the parameters made the test (correctly) fail for FillMode.Forward/FillMode.Both when the end cue isn't 1.0, which is this issue.

@jmacato

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants