private void BuildVisualTree() { // use current position for laying out as we iterate Vector3 currentGridPosition = new Vector3(horizontalSpace, horizontalSpace, 1.0f); Vector2 imageSize = new Vector2(imageDimension, imageDimension); Vector3KeyFrameAnimation firstAnimation = _compositor.CreateVector3KeyFrameAnimation(); firstAnimation.InsertKeyFrame(0.0f, new Vector3(-50.0f, -50.0f, 0.0f)); firstAnimation.InsertKeyFrame(1.0f, currentGridPosition); firstAnimation.Duration = TimeSpan.FromMilliseconds(2000); var animation = _compositor.CreateVector3KeyFrameAnimation(); animation.InsertExpressionKeyFrame(0.0f, "previous.Offset"); animation.InsertExpressionKeyFrame(1.0f, "finalvalue"); animation.DelayTime = TimeSpan.FromMilliseconds(1000); animation.Duration = TimeSpan.FromMilliseconds(1500); Visual previousVisual = null; foreach (Uri profileImageUri in GetProfileUrisForTwitterFollowers("@wincomposition")) { var profileImageVisual = MakeImageVisualforFollower(profileImageUri, imageSize); if (previousVisual == null) { firstAnimation.SetVector3Parameter("finalvalue", currentGridPosition); profileImageVisual.ConnectAnimation("Offset", firstAnimation).Start(); } else { animation.SetReferenceParameter("previous", previousVisual); animation.SetVector3Parameter("finalvalue", currentGridPosition); animation.DelayTime += TimeSpan.FromMilliseconds(300); //50 profileImageVisual.ConnectAnimation("Offset", animation).Start(); } _rootVisual.Children.InsertAtBottom(profileImageVisual); previousVisual = profileImageVisual; #region CalcNextOffset // simple dumb layout currentGridPosition.X += horizontalSpace + imageDimension; if (currentGridPosition.X + imageDimension > this.ActualWidth) { currentGridPosition.X = horizontalSpace; currentGridPosition.Y += imageDimension + verticalSpace; } #endregion } }
public void Start(UIElement newParent, CompositionImage targetImage, ScrollViewer scrollViewer, UIElement animationTarget) { Visual transitionVisual = ElementCompositionPreview.GetElementChildVisual(_parent); ElementCompositionPreview.SetElementChildVisual(_parent, null); // // We need to reparent the transition visual under the new parent. This is important to ensure // it's propertly clipped, etc. // GeneralTransform coordinate = newParent.TransformToVisual(_parent); Point position = coordinate.TransformPoint(new Point(0, 0)); Vector3 currentOffset = transitionVisual.Offset; currentOffset.X -= (float)position.X; currentOffset.Y -= (float)position.Y; transitionVisual.Offset = currentOffset; _parent = newParent; _targetImage = targetImage; // Move the transition visual to it's new parent ElementCompositionPreview.SetElementChildVisual(_parent, transitionVisual); // Hide the target Image now since the handoff visual is still transitioning targetImage.Opacity = 0f; // Load image if necessary _imageLoaded = targetImage.IsContentLoaded; if (!_imageLoaded) { targetImage.ImageOpened += CompositionImage_ImageOpened; } // // Create a scoped batch around the animations. When the batch completes, we know the animations // have finished and we can cleanup the transition related objects. // Compositor compositor = transitionVisual.Compositor; _scopeBatch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); // // Determine the offset between the parent and the target UIElement. This will be used to calculate the // target position we are animating to. // coordinate = targetImage.TransformToVisual(_parent); position = coordinate.TransformPoint(new Point(0, 0)); TimeSpan totalDuration = TimeSpan.FromMilliseconds(1000); Vector3KeyFrameAnimation offsetAnimation = compositor.CreateVector3KeyFrameAnimation(); if (scrollViewer != null) { CompositionPropertySet scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer); // Include the scroller offset as that is a factor position.X += scrollViewer.HorizontalOffset; position.Y += scrollViewer.VerticalOffset; // // Since the target position is relative to the target UIElement which can move, we need to construct // an expression to bind the target's position to the end position of our animation. // string expression = "Vector3(scrollingProperties.Translation.X, scrollingProperties.Translation.Y, 0) + itemOffset"; offsetAnimation.InsertExpressionKeyFrame(1f, expression); offsetAnimation.SetReferenceParameter("scrollingProperties", scrollProperties); offsetAnimation.SetVector3Parameter("itemOffset", new Vector3((float)position.X, (float)position.Y, 0)); offsetAnimation.Duration = totalDuration; } else { offsetAnimation.InsertKeyFrame(1, new Vector3((float)position.X, (float)position.Y, 0)); offsetAnimation.Duration = totalDuration; } // Create size animation to change size of the visual Vector2KeyFrameAnimation sizeAnimation = compositor.CreateVector2KeyFrameAnimation(); sizeAnimation.InsertKeyFrame(1f, new Vector2((float)targetImage.ActualWidth, (float)targetImage.ActualHeight)); sizeAnimation.Duration = totalDuration; // Create the fade in animation for the other page content if (animationTarget != null) { Visual fadeVisual = ElementCompositionPreview.GetElementVisual(animationTarget); ScalarKeyFrameAnimation fadeIn = compositor.CreateScalarKeyFrameAnimation(); fadeIn.InsertKeyFrame(0f, 0.0f); fadeIn.InsertKeyFrame(1f, 1.0f); fadeIn.Duration = totalDuration; fadeVisual.StartAnimation("Opacity", fadeIn); } //Start Animations _sprite.StartAnimation("Size", sizeAnimation); _sprite.StartAnimation("Offset", offsetAnimation); //Scoped batch completed event _scopeBatch.Completed += ScopeBatch_Completed; _scopeBatch.End(); // Clear the flag _animationCompleted = false; }