As we speak a new version of Daily Mail Online is being published to store. I am not going to discuss the content rather stick with code.
I have been testing staged rollout for a week now and that gave me valuable insights. I got errors I could not have reproduced myself. However all this time I was using UWPCommunityToolkit animations – Fade and Offset. Testing out nightly builds post 1.2 release I noticed that the app start time would significantly spiral with initial load taking over 20 seconds. The toolkit animations whilst providing a simple API on the surface are very extensive underneath and talking to folks I decided to create a custom set.
I have in snippet below two border controls
Border b = item.FindDescendantByName("ChannelBackground") as Border; Border separator = item.FindDescendantByName("ChannelSeparator") as Border;
using toolkit extensions I did
b.Offset(offsetY: -65, duration: animationduration).Start(); separator.Fade(1, animationduration).Start();
so after a big round of search and copy pasting code from around the net, I finally had my own set. To make the change easier, I decided to use different method names so I could test individual bits without affecting it all.
b.AnimateOffsetY(-65, animationduration); separator.AnimateOpacity(1, animationduration);
One thing that caught me off guard. To not show separator when XAML loads, I set Opacity to 0. With opacity to set, Composition API could not change its opacity any longer. As a fallback I use Storyboard and they seem to work just fine. Took me a while to figure out so now you will notice that in animation extensions, I check UIElement opacity and set it to 1 if it is zero.
Here is the animation extensions.
public static class AnimationExtensions { public static bool UseCompositionAnimations => ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 2); // SDK >= 10586 public static void AnimateOpacity(this UIElement element, float value, double duration = 150) { if (UseCompositionAnimations) { if (element.Opacity == 0) // composition animations doesn't have any effect if it is zero { element.Opacity = 1; } var xamlVisual = ElementCompositionPreview.GetElementVisual(element); if (duration <= 0) { xamlVisual.Opacity = value; return; } var compositor = xamlVisual.Compositor; var animation = compositor.CreateScalarKeyFrameAnimation(); animation.Duration = TimeSpan.FromMilliseconds(duration); animation.DelayTime = TimeSpan.Zero; animation.InsertKeyFrame(1f, value); xamlVisual.StartAnimation("Opacity", animation); } else { if (duration <= 0) { element.Opacity = value; return; } AnimateDoubleProperty(element, "Opacity", value, duration); } } public static void AnimateOffsetY(this UIElement element, float value, double duration = 150) { if (UseCompositionAnimations) { var xamlVisual = ElementCompositionPreview.GetElementVisual(element); var offsetVector = new Vector3(0, value, 0); if (duration <= 0) { xamlVisual.Offset = offsetVector; return; } var compositor = xamlVisual.Compositor; var animation = compositor.CreateVector3KeyFrameAnimation(); animation.Duration = TimeSpan.FromMilliseconds(duration); animation.DelayTime = TimeSpan.Zero; animation.InsertKeyFrame(1f, offsetVector); xamlVisual.StartAnimation("Offset", animation); } else { var transform = GetAttachedCompositeTransform(element); if (duration <= 0) { transform.TranslateY = value; return; } string path = GetAnimationPath(transform, element, "TranslateY"); AnimateDoubleProperty(element, path, value, duration); } } private static string GetAnimationPath(CompositeTransform transform, UIElement element, string property) { if (element.RenderTransform == transform) { return $"(UIElement.RenderTransform).(CompositeTransform.{property})"; } var group = element.RenderTransform as TransformGroup; if (group == null) { return string.Empty; } for (var index = 0; index < group.Children.Count; index++) { if (group.Children[index] == transform) { return $"(UIElement.RenderTransform).(TransformGroup.Children)[{index}].(CompositeTransform.{property})"; } } return string.Empty; } private static CompositeTransform GetAttachedCompositeTransform(UIElement element) { CompositeTransform compositeTransform = null; if (element.RenderTransform != null) { compositeTransform = element.RenderTransform as CompositeTransform; } if (compositeTransform == null) { compositeTransform = new CompositeTransform(); element.RenderTransform = compositeTransform; } return compositeTransform; } private static Storyboard AnimateDoubleProperty( this DependencyObject target, string property, double to, double duration = 250, EasingFunctionBase easingFunction = null) { var storyboard = new Storyboard(); var animation = new DoubleAnimation { To = to, Duration = TimeSpan.FromMilliseconds(duration), EasingFunction = easingFunction ?? new SineEase(), FillBehavior = FillBehavior.HoldEnd, EnableDependentAnimation = true }; Storyboard.SetTarget(animation, target); Storyboard.SetTargetProperty(animation, property); storyboard.Children.Add(animation); storyboard.FillBehavior = FillBehavior.HoldEnd; storyboard.Begin(); return storyboard; } }
These are very lightweight animations. If you encounter weird slow downs, maybe consider rolling out your own animation extensions like above. Happy coding