/// <summary> /// Determines if <see cref="FrameworkElement"/> should apply layout animation. /// </summary> /// <param name="view">The view to animate.</param> /// <returns> /// <code>true</code> if the layout operation should be animated, /// otherwise <code>false</code>. /// </returns> public bool ShouldAnimateLayout(object view) { if (_shouldAnimateLayout) { var dependencyObject = ViewConversion.GetDependencyObject(view); return(dependencyObject is FrameworkElement frameworkElement && frameworkElement.Parent != null); } return(false); }
/// <summary> /// Create a <see cref="Storyboard"/> to be used to animate the view, /// based on the animation configuration supplied at initialization /// time and the new view position and size. /// </summary> /// <param name="viewManager">The view manager for the view.</param> /// <param name="view">The view to create the animation for.</param> /// <param name="dimensions">The view dimensions.</param> protected override IObservable <Unit> CreateAnimationCore(IViewManager viewManager, object view, Dimensions dimensions) { var element = ViewConversion.GetDependencyObject <UIElement>(view); var animatedProperty = AnimatedProperty; if (animatedProperty.HasValue) { var storyboard = new Storyboard(); var @finally = default(Action); switch (animatedProperty.Value) { case AnimatedPropertyType.Opacity: var opacity = element.Opacity; var fromOpacity = IsReverse ? opacity : 0.0; var toOpacity = IsReverse ? 0.0 : opacity; element.Opacity = fromOpacity; storyboard.Children.Add(CreateDoubleAnimation(element, "Opacity", fromOpacity, toOpacity)); @finally = () => element.Opacity = toOpacity; break; case AnimatedPropertyType.ScaleXY: var fromScale = IsReverse ? 1.0 : 0.0; var toScale = IsReverse ? 0.0 : 1.0; var scaleTransform = new ScaleTransform { CenterX = dimensions.X + dimensions.Width / 2, CenterY = dimensions.Y + dimensions.Height / 2, ScaleX = fromScale, ScaleY = fromScale, }; var originalTransform = element.RenderTransform; var transformGroup = new TransformGroup(); transformGroup.Children.Add(originalTransform); transformGroup.Children.Add(scaleTransform); element.RenderTransform = transformGroup; storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "ScaleX", fromScale, toScale)); storyboard.Children.Add(CreateDoubleAnimation(scaleTransform, "ScaleY", fromScale, toScale)); @finally = () => element.RenderTransform = originalTransform; break; default: throw new InvalidOperationException( "Missing animation for property: " + animatedProperty.Value); } return(new StoryboardObservable(storyboard, @finally)); } throw new InvalidOperationException( "Missing animated property from the animation configuration."); }
/// <summary> /// Create a <see cref="Storyboard"/> to be used to animate the view, /// based on the animation configuration supplied at initialization /// time and the new view position and size. /// </summary> /// <param name="viewManager">The view manager for the view.</param> /// <param name="view">The view to create the animation for.</param> /// <param name="dimensions">The view dimensions.</param> /// <returns>The storyboard.</returns> protected override IObservable <Unit> CreateAnimationCore(IViewManager viewManager, object view, Dimensions dimensions) { var currentDimensions = viewManager.GetDimensions(view); var animateLocation = dimensions.X != currentDimensions.X || dimensions.Y != currentDimensions.Y; var animateSize = dimensions.Width != currentDimensions.Width || dimensions.Height != currentDimensions.Height; if (!animateLocation && !animateSize) { return(null); } var element = ViewConversion.GetDependencyObject(view); var storyboard = new Storyboard(); if (currentDimensions.X != dimensions.X) { storyboard.Children.Add( CreateTimeline(element, "(Canvas.Left)", currentDimensions.X, dimensions.X)); } if (currentDimensions.Y != dimensions.Y) { storyboard.Children.Add( CreateTimeline(element, "(Canvas.Top)", currentDimensions.Y, dimensions.Y)); } if (currentDimensions.Width != dimensions.Width) { var timeline = CreateTimeline(element, "Width", currentDimensions.Width, dimensions.Width); #if WINDOWS_UWP timeline.EnableDependentAnimation = true; #endif storyboard.Children.Add(timeline); } if (currentDimensions.Height != dimensions.Height) { var timeline = CreateTimeline(element, "Height", currentDimensions.Height, dimensions.Height); #if WINDOWS_UWP timeline.EnableDependentAnimation = true; #endif storyboard.Children.Add(timeline); } return(new StoryboardObservable(storyboard, () => { viewManager.SetDimensions(element, dimensions); })); }
/// <summary> /// Animate a view deletion using the layout animation configuration /// supplied during initialization. /// </summary> /// <param name="viewManager">The view manager for the native view.</param> /// <param name="view">The view to animate.</param> /// <param name="finally"> /// Called once the animation is finished, should be used to completely /// remove the view. /// </param> public void DeleteView(IViewManager viewManager, object view, Action @finally) { DispatcherHelpers.AssertOnDispatcher(); var layoutAnimation = _layoutDeleteAnimation; var animation = layoutAnimation.CreateAnimation(viewManager, view, viewManager.GetDimensions(view)); if (animation != null) { var element = ViewConversion.GetDependencyObject <UIElement>(view); element.IsHitTestVisible = false; StartAnimation(view, animation.Finally(@finally)); } else { @finally(); } }
/// <summary> /// Adds a child at the given index. /// </summary> /// <param name="parent">The parent view.</param> /// <param name="child">The child view.</param> /// <param name="index">The index.</param> public void AddView(object parent, object child, int index) { var span = (Span)parent; var dependencyObject = ViewConversion.GetDependencyObject(child); var inlineChild = dependencyObject as Inline; if (inlineChild == null) { inlineChild = new InlineUIContainer { Child = dependencyObject.As <UIElement>(), }; } #if WINDOWS_UWP span.Inlines.Insert(index, inlineChild); #else ((IList)span.Inlines).Insert(index, inlineChild); #endif }