Skip to content

Commit

Permalink
Merge pull request #6792 from unoplatform/dev/dr/scrollBarsFlickers
Browse files Browse the repository at this point in the history
Fix visual transition support
  • Loading branch information
mergify[bot] authored Aug 19, 2021
2 parents 26cdaeb + 9c948d9 commit bd0f948
Show file tree
Hide file tree
Showing 10 changed files with 526 additions and 272 deletions.
197 changes: 101 additions & 96 deletions build/PackageDiffIgnore.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3832,105 +3832,110 @@
</IgnoreSet>

<IgnoreSet baseVersion="3.9.7">
<Types>
</Types>
<Methods>
<!-- Focus management -->
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorBrush..ctor(Windows.UI.Composition.Compositor compositor)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStop..ctor()"
reason="Should not be public" />
<Member
fullName="System.UInt32 Windows.UI.Composition.CompositionColorGradientStopCollection.get_Size()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStopCollection.set_Count(System.Int32 value)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStopCollection.set_IsReadOnly(System.Boolean value)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStopCollection..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionEllipseGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Numerics.Vector2 Windows.UI.Composition.CompositionGradientBrush.get_AnchorPoint()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionGradientBrush.set_AnchorPoint(System.Numerics.Vector2 value)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionGradientBrush..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionLinearGradientBrush..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionLineGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionRadialGradientBrush..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionRectangleGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionRoundedRectangleGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionSurfaceBrush..ctor(Windows.UI.Composition.Compositor compositor)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionSurfaceBrush..ctor(Windows.UI.Composition.Compositor compositor, Windows.UI.Composition.ICompositionSurface surface)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionViewBox..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.InsetClip..ctor(Windows.UI.Composition.Compositor compositor)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Xaml.Input.InertiaExpansionBehavior..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Xaml.Input.InertiaRotationBehavior..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Xaml.Input.InertiaTranslationBehavior..ctor()"
reason="Should not be public" />

<Member
fullName="Windows.UI.Xaml.Controls.Primitives.PlacementMode Windows.UI.Xaml.Controls.ToolTipService.GetPlacement(Windows.UI.Xaml.DependencyObject element)"
reason="INVALID REMOVE, TO ADJUST" />
<Member
fullName="System.Void Windows.UI.Xaml.Controls.ToolTipService.SetPlacement(Windows.UI.Xaml.DependencyObject element, Windows.UI.Xaml.Controls.Primitives.PlacementMode value)"
reason="INVALID REMOVE, TO ADJUST" />
<Member
fullName="System.Object Windows.UI.Xaml.Controls.ToolTipService.GetToolTip(Windows.UI.Xaml.DependencyObject element)"
reason="INVALID REMOVE, TO ADJUST" />

<Member
fullName="System.Void Windows.UI.Xaml.Controls.ToolTipService.SetToolTip(Windows.UI.Xaml.DependencyObject element, System.Object value)"
reason="INVALID REMOVE, TO ADJUST" />
<Member
fullName="System.Boolean Windows.UI.Xaml.Controls.VirtualizingPanelLayout.ShouldInsertReorderingView(System.Double physicalExtentOffset)"
reason="INVALID REMOVE, TO ADJUST" />
<Methods>
<Member
fullName="Windows.UI.Xaml.Media.Animation.Timeline/TimelineState Windows.UI.Xaml.Media.Animation.Timeline.get_State()"
reason="Not part of the UWP API" />
<Member
fullName="System.Void Windows.UI.Xaml.Media.Animation.Timeline.set_State(Windows.UI.Xaml.Media.Animation.Timeline/TimelineState value)"
reason="Not part of the UWP API" />
<!-- Focus management -->
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorBrush..ctor(Windows.UI.Composition.Compositor compositor)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStop..ctor()"
reason="Should not be public" />
<Member
fullName="System.UInt32 Windows.UI.Composition.CompositionColorGradientStopCollection.get_Size()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStopCollection.set_Count(System.Int32 value)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStopCollection.set_IsReadOnly(System.Boolean value)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionColorGradientStopCollection..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionEllipseGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Numerics.Vector2 Windows.UI.Composition.CompositionGradientBrush.get_AnchorPoint()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionGradientBrush.set_AnchorPoint(System.Numerics.Vector2 value)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionGradientBrush..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionLinearGradientBrush..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionLineGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionRadialGradientBrush..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionRectangleGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionRoundedRectangleGeometry..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionSurfaceBrush..ctor(Windows.UI.Composition.Compositor compositor)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionSurfaceBrush..ctor(Windows.UI.Composition.Compositor compositor, Windows.UI.Composition.ICompositionSurface surface)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.CompositionViewBox..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Composition.InsetClip..ctor(Windows.UI.Composition.Compositor compositor)"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Xaml.Input.InertiaExpansionBehavior..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Xaml.Input.InertiaRotationBehavior..ctor()"
reason="Should not be public" />
<Member
fullName="System.Void Windows.UI.Xaml.Input.InertiaTranslationBehavior..ctor()"
reason="Should not be public" />

<Member
fullName="Windows.UI.Xaml.Controls.Primitives.PlacementMode Windows.UI.Xaml.Controls.ToolTipService.GetPlacement(Windows.UI.Xaml.DependencyObject element)"
reason="INVALID REMOVE, TO ADJUST" />
<Member
fullName="System.Void Windows.UI.Xaml.Controls.ToolTipService.SetPlacement(Windows.UI.Xaml.DependencyObject element, Windows.UI.Xaml.Controls.Primitives.PlacementMode value)"
reason="INVALID REMOVE, TO ADJUST" />
<Member
fullName="System.Object Windows.UI.Xaml.Controls.ToolTipService.GetToolTip(Windows.UI.Xaml.DependencyObject element)"
reason="INVALID REMOVE, TO ADJUST" />

<Member
fullName="System.Void Windows.UI.Xaml.Controls.ToolTipService.SetToolTip(Windows.UI.Xaml.DependencyObject element, System.Object value)"
reason="INVALID REMOVE, TO ADJUST" />
<Member
fullName="System.Boolean Windows.UI.Xaml.Controls.VirtualizingPanelLayout.ShouldInsertReorderingView(System.Double physicalExtentOffset)"
reason="INVALID REMOVE, TO ADJUST" />

</Methods>
<Fields>
</Fields>
<Properties>
<Member
</Methods>
<Properties>
<Member
fullName="Windows.UI.Xaml.Media.Animation.Timeline/TimelineState Windows.UI.Xaml.Media.Animation.Timeline::State()"
reason="Not part of the UWP API" />
<Member
fullName="System.UInt32 Windows.UI.Composition.CompositionColorGradientStopCollection::Size()"
reason="Method not in UWP contract" />
<Member
fullName="System.Numerics.Vector2 Windows.UI.Composition.CompositionGradientBrush::AnchorPoint()"
reason="Method not in UWP contract" />
</Properties>
<Member
fullName="System.Numerics.Vector2 Windows.UI.Composition.CompositionGradientBrush::AnchorPoint()"
reason="Method not in UWP contract" />
</Properties>
</IgnoreSet>
<!--
Supported nodes (please keep at the bottom of this file):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Uno.Extensions;

namespace Uno.UI.Tests.Windows_UI_Xaml.VisualStateManagerTests
{
Expand Down Expand Up @@ -137,6 +139,155 @@ public void When_UsingStateTriggerAndStoryboard()
completed2Count.Should().Be(1);
}

[TestMethod]
public void When_SetterAffectsSameProperty_Then_OriginalValueNotRestored()
{
var (control, group) = Setup();

var tags = new List<string> { (string)control.Tag };
control.RegisterPropertyChangedCallback(Control.TagProperty, (_, __) => tags.Add((string)control.Tag));

VisualStateManager.GoToState(control, "state1", true);
VisualStateManager.GoToState(control, "state2", true);

Assert.IsTrue(new[] { "initial", "state1", "state2" }.SequenceEqual(tags));
}

[TestMethod]
public void When_NoSetter_Then_OriginalValueRestored()
{
var (control, group) = Setup();
group.States[1].Setters.Clear();

var tags = new List<string> { (string)control.Tag };
control.RegisterPropertyChangedCallback(Control.TagProperty, (_, __) => tags.Add((string)control.Tag));

VisualStateManager.GoToState(control, "state1", true);
VisualStateManager.GoToState(control, "state2", true);

Assert.IsTrue(new[] { "initial", "state1", "initial" }.SequenceEqual(tags));
}

[TestMethod]
public void When_GoToStateWhileTransitionning_Then_StopTransition()
{
var (control, group) = Setup();
var transition = Transition(control, to: 1, frames: 5);
group.Transitions.Add(transition);

VisualStateManager.GoToState(control, "state1", true);
Assert.IsTrue(transition.Storyboard.State == Timeline.TimelineState.Active);

VisualStateManager.GoToState(control, "state2", true);
Assert.IsTrue(transition.Storyboard.State == Timeline.TimelineState.Stopped);
}

[TestMethod]
public void When_GoToStateWhileAnimating_Then_StopAnimation()
{
var (control, group) = Setup();
var animation = group.States[0].Storyboard = AnimateTag(control, "state1", 5);

VisualStateManager.GoToState(control, "state1", true);
Assert.IsTrue(animation.State == Timeline.TimelineState.Active);

VisualStateManager.GoToState(control, "state2", true);
Assert.IsTrue(animation.State == Timeline.TimelineState.Stopped);
}

[TestMethod]
public void When_TransitionAndSetter_Then_SetterAppliedAfter()
{
var (control, group) = Setup();
group.Transitions.Add(Transition(control, from: 1, to: 2, frames: 0));

var tags = new List<string> { (string)control.Tag };
control.RegisterPropertyChangedCallback(Control.TagProperty, (_, __) => tags.Add((string)control.Tag));

VisualStateManager.GoToState(control, "state1", true);
VisualStateManager.GoToState(control, "state2", true);

Assert.IsTrue(new [] { "initial", "state1", "transition_from_state1_to_state2_frame_0", "state2" }.SequenceEqual(tags));
}

[TestMethod]
public void When_TransitionAndSetter_InCompatibilityMode_Then_SetterAppliedBefore()
{
try
{
FeatureConfiguration.VisualState.ApplySettersBeforeTransition = true;

var (control, group) = Setup();
group.Transitions.Add(Transition(control, from: 1, to: 2, frames: 0));

var tags = new List<string> { (string)control.Tag };
control.RegisterPropertyChangedCallback(Control.TagProperty, (_, __) => tags.Add((string)control.Tag));

VisualStateManager.GoToState(control, "state1", true);
VisualStateManager.GoToState(control, "state2", true);

Assert.IsTrue(new[] { "initial", "state1", "state2", "transition_from_state1_to_state2_frame_0" }.SequenceEqual(tags));
}
finally
{
FeatureConfiguration.VisualState.ApplySettersBeforeTransition = false;
}
}

private static (Control control, VisualStateGroup states) Setup()
{
var control = new Control { Name = "control", Tag = "initial", Template = new ControlTemplate(() => new Grid()) };
var group = new VisualStateGroup { States = { State(1), State(2) } };

VisualStateManager.SetVisualStateGroups((FrameworkElement)control.TemplatedRoot, new List<VisualStateGroup> { group });

control.ApplyTemplate();

return (control, group);
}

private static VisualState State(int id)
=> new VisualState
{
Name = "state" + id,
Setters = {new Setter(new TargetPropertyPath("control", "Tag"), "state" + id)}
};

private static VisualTransition Transition(Control control, int? @from = null, int? to = null, params int[] frames)
{
var transition = new VisualTransition();
var animationName = "transition";

if (@from is int f)
{
transition.From = "state" + f;
animationName += "_from_state" + f;
}

if (to is int t)
{
transition.To = "state" + t;
animationName += "_to_state" + t;
}

transition.Storyboard = AnimateTag(control, animationName, frames);

return transition;
}

private static Storyboard AnimateTag(Control target, string name, params int[] frames)
{
var anim = new ObjectAnimationUsingKeyFrames();
Storyboard.SetTarget(anim, target);
Storyboard.SetTargetProperty(anim, "Tag");
foreach (var frame in frames)
{
anim.KeyFrames.Add(new DiscreteObjectKeyFrame { KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(frame)), Value = $"{name}_frame_{frame}" });
}

return new Storyboard { Children = { anim } };
}

private class CustomStateTrigger : StateTrigger
{
internal CustomStateTrigger(bool initialState = true)
Expand Down
10 changes: 10 additions & 0 deletions src/Uno.UI/FeatureConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,16 @@ public static class UIElement
#endif
}

public static class VisualState
{
/// <summary>
/// When this is set, the <see cref="Windows.UI.Xaml.VisualState.Setters"/> will be applied synchronously when changing state,
/// unlike UWP which waits the for the end of the <see cref="VisualTransition.Storyboard"/> (if any) to apply them.
/// </summary>
/// <remarks>This flag is for backward compatibility with old versions of uno and should not be turned on.</remarks>
public static bool ApplySettersBeforeTransition { get; set; } = false;
}

public static class WebView
{
#if __ANDROID__
Expand Down
Loading

0 comments on commit bd0f948

Please sign in to comment.