unoplatform / uno

Open-source platform for building cross-platform native Mobile, Web, Desktop and Embedded apps quickly. Create rich, C#/XAML, single-codebase apps from any IDE. Hot Reload included! 90m+ NuGet Downloads!!
https://platform.uno
Apache License 2.0
8.91k stars 722 forks source link

Unable to animate the `Canvas.Top` or `Canvas.Left` attached properties #12301

Closed BrianDT closed 10 months ago

BrianDT commented 1 year ago

Current behavior

Animation of the canvas top or left attached properties does not work on WASM, Android and iOS.


    <Storyboard x:Name="SimpleStoryboard">
        <DoubleAnimation Storyboard.TargetName="Thing" 
                         Storyboard.TargetProperty="(Canvas.Top)"
                         From="{x:Bind VM.Y, Mode=OneWay}" To="20.0" Duration="0:0:5"/>
    </Storyboard>

On button press

this.SimpleStoryboard.Begin();

Works perfectly well on WinUI

Expected behavior

In the sample the red ball should animate vertically up the screen.

How to reproduce it (as minimally and precisely as possible)

Reproduced in sample at https://github.com/BrianDT/UnoCanvasOffsetAnimationIssue

Workaround

Adding EnableDependentAnimation="true" to the DoubleAnimation works for WASM and iOS

Works on UWP/WinUI

Yes

Environment

Uno.UI / Uno.UI.WebAssembly / Uno.UI.Skia, Uno.WinUI / Uno.WinUI.WebAssembly / Uno.WinUI.Skia

NuGet package version(s)

4.8.33

Affected platforms

All targets

IDE

Visual Studio 2022

IDE version

17.5.5

Relevant plugins

None

Anything else we need to know?

Youssef1313 commented 1 year ago

Looks like a dupe of https://github.com/unoplatform/uno/issues/8613

BrianDT commented 1 year ago

Looks like a dupe of #8613

@Youssef1313 Superficially looks the same but actually not. #8613 suggests that if you add EnableDependentAnimation="true"

To the DoubleAnimation then the problem can be worked around. This works for WASM but is not true for Android where the EnableDependentAnimation has no effect and it still does not work. Jury is still out on iOS.

Even for WASM, there is no suggestion under #8613 that anybody has raised a WinUI issue indicating that WinUI should require the EnableDependentAnimation property set to work, which makes be thing that if WinUI is correct the workaround is just covering up what is still an issue.

MartinZikmund commented 1 year ago

Yes, will close #8613 in favor of this one, as it is more broad, affecting all targets

dr1rrb commented 1 year ago

@BrianDT The EnableDependentAnimation is a UWP/WInUI flag which is false by default and indicates if animations that are invalidating the layout (i.e. causing Measure/Arrange phases) are allowed or not (cf. https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.animation.doubleanimation.enabledependentanimation?view=winrt-22621#whats-considered-a-dependent-animation).

I assume that this flag has to be set to true to animate the Canvas.<X|Y> on Windows, and we should align Uno's behavior with Windows (even if currently we are not running animation independently of the UI thread on Skia and Wasm).

DoubleAnimation.EnableDependentAnimation Property (Windows.UI.Xaml.Media.Animation) - Windows UWP applications
Gets or sets a value that declares whether animated properties that are considered dependent animations should be permitted to use this animation declaration.
BrianDT commented 1 year ago

@dr1rrb I absolutely agree that Uno's behavior should align with Windows, that was the point I was trying to make. The point is that Windows Does Not Require the EnableDependentAnimation flag set for the animation to run, so I was questioning why it was required in Uno.

BrianDT commented 1 year ago

A sequence of changes to the sample has enabled the iOS build to be investigated. The path has been shortened, the provisioning profile has been reset and changes from the latest templates incorporated. The sample now shows that if EnableDependentAnimation="true" the iOS build executes as expected. Therefore, in summary: Windows OK Android Fail iOS OK with workaround WASM OK with workaround

dr1rrb commented 1 year ago

@dr1rrb I absolutely agree that Uno's behavior should align with Windows, that was the point I was trying to make. The point is that Windows Does Not Require the EnableDependentAnimation flag set for the animation to run, so I was questioning why it was required in Uno.

Indeed, animating (Canvas.<Top|Left>) is working on windows even if the EnableDependentAnimation is not set to true ... I was convinced that this should be considered as a dependent animation. And apparently when we implemented the animations in Uno we did the same mistake. This is definitely a bug in uno (and will probably require a refactor of the Canvas to make sure to be able to runs those animation independently).

For reference :

An animation is independent if it has any of these characteristics:

  • The Duration of the animation is 0 seconds (see Warning)
  • The animation targets UIElement.Opacity
  • The animation targets a sub-property value of these UIElement properties: Transform3D, RenderTransform, Projection, Clip
  • The animation targets Canvas.Left or Canvas.Top
  • The animation targets a Brush value and uses a SolidColorBrush, animating its Color
  • The animation is an ObjectAnimationUsingKeyFrames

https://learn.microsoft.com/en-us/windows/apps/design/motion/storyboarded-animations#dependent-and-independent-animations

About the fact that the animation is not working on Android (even with the flag), this is strange and probably another bug ... do you have anything in the log?

BTW as a workaround (and a more performant approach for iOS and Android considering current support in uno), you should consider to use RenderTransform instead of Canvas.<Top|Left>.

Storyboarded animations - Windows apps
Learn how to use storyboarded animations to change the value of a dependency property as a function of time.
BrianDT commented 1 year ago

@dr1rrb The suggestion to use a Translation Transform for the animation is a good one. This works absolutely fine on Windows and WASM, but has a minor issue on Android and a slightly bigger issue on iOS.

The sample has been updated to include the alternative animation. In the sample only the Translate.Y is animated.

On Android when the animation completes the Translate.X is set to 0 so the target object that has been moved shifts to the left of the screen.

On iOS the Translate.X is set to 0 as soon as the animation starts so the target object moves up the left-hand side of the screen.

dr1rrb commented 1 year ago

@BrianDT Damn just realized that you are probably facing a known issue where animating 2 properties of the same object on those platforms causes some trouble https://github.com/unoplatform/uno/blob/master/doc/articles/features/working-with-animations.md#general-guidelines :/

The workaround is to have a layer for each animated value:

<Border>
    <Border.RenderTransform>
        <TranslateTransform x:Name="xTransform" X="0" />
    </Border.RenderTransform>
    <Border>
        <Border.RenderTransform>
            <TranslateTransform x:Name="yTransform" Y="0" />
        </Border.RenderTransform>

        <Your_Content />

    </Border>
</Border>

... which is incredibly ugly :/

You should upvote this https://github.com/unoplatform/uno/issues/12530

GitHub
uno/working-with-animations.md at master · unoplatform/uno
Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported. - uno/working-with-animations.md at master · unoplatform/uno