Smooth Interaction and Motion with the Visual Layer
The Composition APIs come with a robust animation engine that provides quick and fluid motion running in a separate process from your Universal Windows Platform (UWP) app. This provides a consistent 60 frames per second when running your app on an IoT device as well as on a screaming gaming machine. It is, quite simply, fast.
The Composition APIs also provide something you probably have never had access to before: the ability to create high-performing, low-level manipulation-driven custom animations like the one shown above. Preview releases of the Composition APIs have already given you the ability to control animations with the XAML ScrollViewer’s ManipulationPropertySet. The Windows 10 Anniversary Update allows you to go even further, with the goal of empowering developers to use many types of input to drive animation.
This post will briefly cover the basics of expression animations. It will move on to a demonstration of how to drive expression animations from a ScrollViewer ManipulationPropertySet and, more importantly, why you really want to even if you don’t realize it yet. Finally, it will touch on the new InteractionTracker and give you an indication of just how much more powerful you are today as a developer than you were at the end of July.
A fast and fluid overview of expression animations
The Visual Layer supports both keyframe animations as well as expression animations. If you have worked with XAML animations before, then you are probably already familiar with how keyframes work. In a keyframe animation, you set values for some property you want to change over time and also assign the duration for the change: in the example below, a start value, a middle value, and then an ending value. The animation system will take care of tweening your animation – in other words, generating all the values between the ones you have explicitly specified.
ScalarKeyFrameAnimation blurAnimation = _compositor.CreateScalarKeyFrameAnimation(); blurAnimation.InsertKeyFrame(0.0f, 0.0f); blurAnimation.InsertKeyFrame(0.5f, 100.0f); blurAnimation.InsertKeyFrame(1.0f, 0.0f); blurAnimation.Duration = TimeSpan.FromSeconds(4); blurAnimation.IterationBehavior = AnimationIterationBehavior.Forever; _brush.StartAnimation("Blur.BlurAmount", blurAnimation);
A keyframe animation is a fire-and-forget mechanism that is time based. There are situations, however, when you need your animations to be coordinated and actually driving each other instead of simply moving in synchronized fashion.
In the demo above (source code), each gray gear is animated based on the animation of the gear preceding it. If the preceding gear suddenly goes faster or reverses direction, it forces the following gear to do the same. A keyframe animations can’t create motion effects that work in this way, but expression animations can. They are able to do so because, while keyframe animations are time based, expression animations are reference based.
The critical code that hooks up the gears for animation in the demo is found in the following section that calls the CreateExpressionAnimation method on the Compositor instance. The expression basically says that the animation should reference and be driven by the RotationAngleInDegrees property of the Visual that is indicated by the parameter “previousGear”. In the next line, the reference parameter is assigned. In the final line, the current Visual’s RotationAngleInDegrees property is finally animated based on the value referred to in the ExpressionAnimation object.
private void ConfigureGearAnimation(Visual currentGear, Visual previousGear) { // If rotation expression is null then create an expression of a gear rotating the opposite direction _rotationExpression = _rotationExpression ?? _compositor.CreateExpressionAnimation("-previousGear.RotationAngleInDegrees"); // put in placeholder parameters _rotationExpression.SetReferenceParameter("previousGear", previousGear); // Start the animation based on the Rotation Angle in Degrees. currentGear.StartAnimation("RotationAngleInDegrees", _rotationExpression); }
But if an animation can be driven by another animation, you may be wondering, couldn’t we also drive an animation with something more concrete like user input? Why, yes. Yes, we can.
The beauty of the ScrollViewer ManipulationPropertySet
Driving an animation from a ScrollViewer using XAML-Composition interop is fairly easy. With just a few lines of code, you can add an animation to a pre-existing ScrollViewer control by taking advantage of the GetScrollViewerManipulationPropertySet method on the ElementCompositionPreview class.
You would use this technique if you wanted to add a parallax effect to your XAML or to create a sticky header that stays in place as content scrolls beneath it. In the demo illustrated below (source code), a ScrollViewer is even used to drive a parallax effect on a ListView.
Adding parallax behavior to a XAML page can be accomplished in just a few lines, as the following sample code by James Clarke demonstrates.
CompositionPropertySet scrollerManipProps = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(myScroller); Compositor compositor = scrollerManipProps.Compositor; // Create the expression ExpressionAnimation expression = compositor.CreateExpressionAnimation("scroller.Translation.Y * parallaxFactor"); // wire the ParallaxMultiplier constant into the expression expression.SetScalarParameter("parallaxFactor", 0.3f); // set "dynamic" reference parameter that will be used to evaluate the current position of the scrollbar every frame expression.SetReferenceParameter("scroller", scrollerManipProps); // Get the background image and start animating it's offset using the expression Visual backgroundVisual = ElementCompositionPreview.GetElementVisual(background); backgroundVisual.StartAnimation("Offset.Y", expression);
The even more beautiful InteractionTracker
Driving expression animations with a ScrollViewer is extremely powerful, but what if you want to drive animations using touch gestures instead? What if you want to pull items toward you with your finger, as in the demo below (source code), or animate multiple flying images across and into the screen as happens in the demo at the top of this post (source code)?
In order to achieve these effects, you would use the new InteractionTracker and VisualInteractionSource classes. InteractionTracker is a state machine that can be driven by active input. This is what you hook up to your animations. The VisualInteractionSource class, on the other hand, determines what kind of input you will use to drive your InteractionTracker.
The following sample code demonstrates a basic implementation of an InteractionTracker that is driven by touch input. The viewportVisual is simply the backing Visual for the root element on the page. You use this as the VisualInteractionSource for the tracker. In doing so, you specify that you are tracking X and Y manipulations. You also indicate that you want to track inertial movement.
_tracker = InteractionTracker.Create(_compositor); var interactionSource = VisualInteractionSource.Create(viewportVisual); interactionSource.PositionXSourceMode = InteractionSourceMode.EnabledWithInertia; interactionSource.PositionYSourceMode = InteractionSourceMode.EnabledWithInertia; _tracker.InteractionSources.Add(interactionSource);
Hooking the tracker up to an expression animation works basically the same way as hooking up a gear Visual to another gear Visual, as you did earlier. You call the CreateExpressionAnimation factory method on the current Compositor and reference the Position property of the tracker. You then animate the Offset property of the Visual you want to add motion to your expression.
var positionExpression = _compositor.CreateExpressionAnimation("-tracker.Position"); positionExpression.SetReferenceParameter("tracker", _tracker); contentVisual.StartAnimation("Offset", positionExpression);
Those are the basics of driving animation from almost any input. What you do with this amazing new power is entirely up to you.
Wrapping up
Expression animations and Visual Layer Interactions are both topics that can become very deep, very fast. To help you through these deeper waters, we highly recommend the following videos and articles:
- Fun with Expressions
- Using Expression Animations to Create Engaging and Custom UI
- Adding Interactions in the Visual Layer to Create Customized and Responsive Experiences
- Visual Layer – Mocking up the Lock Screen
Get started now – download Visual Studio.
The Windows team would love to hear your feedback. Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.