|
- using BPA.UIControl.Commons.KnownBoxes;
- using System;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- using System.Windows.Media.Animation;
-
- namespace BPA.UIControl
- {
- /// <summary>
- /// 转换动画
- /// </summary>
- public class Transition : ContentControl
- {
- static Transition()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(Transition), new FrameworkPropertyMetadata(typeof(Transition)));
- }
-
- /// <inheritdoc/>
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
-
- Loaded += Transition_Loaded;
- }
-
- private void Transition_Loaded(object sender, RoutedEventArgs e)
- {
- if (IsShow && Type != TransitionType.None)
- {
- ShowAnimation(this);
-
- if (!PlayEveryTime)
- {
- Loaded -= Transition_Loaded;
- }
- }
- else if (Type >= TransitionType.CollapseUp && Type <= TransitionType.CollapseRight && CollapsedSize > 0)
- {
- if (Content is FrameworkElement element)
- {
- Progress = CollapsedSize / element.ActualWidth;
- }
- }
-
- Loaded -= Transition_Loaded;
- }
-
- #region 命令
-
- /// <summary>
- /// 显示完命令
- /// </summary>
- public static readonly DependencyProperty ShowedCommandProperty =
- DependencyProperty.Register("ShowedCommand", typeof(ICommand), typeof(Transition), new PropertyMetadata(default(ICommand)));
-
- /// <summary>
- /// 显示完命令
- /// </summary>
- public ICommand ShowedCommand
- {
- get { return (ICommand)GetValue(ShowedCommandProperty); }
- set { SetValue(ShowedCommandProperty, value); }
- }
-
- /// <summary>
- /// 关闭完命令
- /// </summary>
- public static readonly DependencyProperty ClosedCommandProperty =
- DependencyProperty.Register("ClosedCommand", typeof(ICommand), typeof(Transition), new PropertyMetadata(default(ICommand)));
-
- /// <summary>
- /// 关闭完命令
- /// </summary>
- public ICommand ClosedCommand
- {
- get { return (ICommand)GetValue(ClosedCommandProperty); }
- set { SetValue(ClosedCommandProperty, value); }
- }
-
- #endregion 命令
-
- #region 事件
-
- /// <summary>
- /// 显示完事件
- /// </summary>
- public static readonly RoutedEvent ShowedEvent =
- EventManager.RegisterRoutedEvent("Showed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Transition));
-
- /// <summary>
- /// 显示完事件 handler
- /// </summary>
- public event RoutedEventHandler Showed
- {
- add { AddHandler(ShowedEvent, value); }
- remove { RemoveHandler(ShowedEvent, value); }
- }
-
- /// <summary>
- /// 关闭完事件
- /// </summary>
- public static readonly RoutedEvent ClosedEvent =
- EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Transition));
-
- /// <summary>
- /// 关闭完事件 handler
- /// </summary>
- public event RoutedEventHandler Closed
- {
- add { AddHandler(ClosedEvent, value); }
- remove { RemoveHandler(ClosedEvent, value); }
- }
-
- #endregion 事件
-
- #region 依赖属性
-
- /// <summary>
- /// 是否显示
- /// </summary>
- public static readonly DependencyProperty IsShowProperty =
- DependencyProperty.Register("IsShow", typeof(bool), typeof(Transition), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsShowChanged));
-
- /// <summary>
- /// 是否显示
- /// </summary>
- public bool IsShow
- {
- get { return (bool)GetValue(IsShowProperty); }
- set { SetValue(IsShowProperty, BooleanBoxes.Box(value)); }
- }
-
- /// <summary>
- /// 每次加载显示动画
- /// </summary>
- public static readonly DependencyProperty PlayEveryTimeProperty =
- DependencyProperty.Register("PlayEveryTime", typeof(bool), typeof(Transition), new PropertyMetadata(BooleanBoxes.FalseBox));
-
- /// <summary>
- /// 每次加载显示动画
- /// </summary>
- public bool PlayEveryTime
- {
- get { return (bool)GetValue(PlayEveryTimeProperty); }
- set { SetValue(PlayEveryTimeProperty, BooleanBoxes.Box(value)); }
- }
-
- /// <summary>
- /// 转换类型
- /// </summary>
- public static readonly DependencyProperty TypeProperty =
- DependencyProperty.Register("Type", typeof(TransitionType), typeof(Transition), new PropertyMetadata(default(TransitionType)));
-
- /// <summary>
- /// 转换类型
- /// </summary>
- public TransitionType Type
- {
- get { return (TransitionType)GetValue(TypeProperty); }
- set { SetValue(TypeProperty, value); }
- }
-
- /// <summary>
- /// 动画时长
- /// </summary>
- public static readonly DependencyProperty DurationProperty =
- DependencyProperty.Register("Duration", typeof(Duration), typeof(Transition), new PropertyMetadata(default(Duration)));
-
- /// <summary>
- /// 动画时长
- /// </summary>
- public Duration Duration
- {
- get { return (Duration)GetValue(DurationProperty); }
- set { SetValue(DurationProperty, value); }
- }
-
- /// <summary>
- /// 动画位置偏移
- /// </summary>
- public static readonly DependencyProperty OffsetProperty =
- DependencyProperty.Register("Offset", typeof(double), typeof(Transition), new PropertyMetadata(default(double)));
-
- /// <summary>
- /// 动画位置偏移
- /// </summary>
- public double Offset
- {
- get { return (double)GetValue(OffsetProperty); }
- set { SetValue(OffsetProperty, value); }
- }
-
- /// <summary>
- /// 动画初始缩放
- /// </summary>
- public static readonly DependencyProperty InitialScaleProperty =
- DependencyProperty.Register("InitialScale", typeof(double), typeof(Transition), new PropertyMetadata(default(double)));
-
- /// <summary>
- /// 动画初始缩放
- /// </summary>
- public double InitialScale
- {
- get { return (double)GetValue(InitialScaleProperty); }
- set { SetValue(InitialScaleProperty, value); }
- }
-
- /// <summary>
- /// 显示缓动
- /// </summary>
- public static readonly DependencyProperty ShowEasingFunctionProperty =
- DependencyProperty.Register("ShowEasingFunction", typeof(IEasingFunction), typeof(Transition), new PropertyMetadata(default(IEasingFunction)));
-
- /// <summary>
- /// 显示缓动
- /// </summary>
- public IEasingFunction ShowEasingFunction
- {
- get { return (IEasingFunction)GetValue(ShowEasingFunctionProperty); }
- set { SetValue(ShowEasingFunctionProperty, value); }
- }
-
- /// <summary>
- /// 关闭缓动
- /// </summary>
- public static readonly DependencyProperty CloseEasingFunctionProperty =
- DependencyProperty.Register("CloseEasingFunction", typeof(IEasingFunction), typeof(Transition), new PropertyMetadata(default(IEasingFunction)));
-
- /// <summary>
- /// 关闭缓动
- /// </summary>
- public IEasingFunction CloseEasingFunction
- {
- get { return (IEasingFunction)GetValue(CloseEasingFunctionProperty); }
- set { SetValue(CloseEasingFunctionProperty, value); }
- }
-
- /// <summary>
- /// 动画进度
- /// 显示完成 = 1
- /// 隐藏完成 = 0
- /// </summary>
- public static readonly DependencyProperty ProgressProperty =
- DependencyProperty.Register("Progress", typeof(double), typeof(Transition), new PropertyMetadata(default(double)));
-
- /// <summary>
- /// 动画进度
- /// 显示完成 = 1
- /// 隐藏完成 = 0
- /// </summary>
- public double Progress
- {
- get { return (double)GetValue(ProgressProperty); }
- set { SetValue(ProgressProperty, value); }
- }
-
- /// <summary>
- /// 是否淡入淡出
- /// </summary>
- public static readonly DependencyProperty IsFadeProperty =
- DependencyProperty.Register("IsFade", typeof(bool), typeof(Transition), new PropertyMetadata(BooleanBoxes.FalseBox));
-
- /// <summary>
- /// 是否淡入淡出
- /// </summary>
- public bool IsFade
- {
- get { return (bool)GetValue(IsFadeProperty); }
- set { SetValue(IsFadeProperty, BooleanBoxes.Box(value)); }
- }
-
- /// <summary>
- /// 折叠后的大小
- /// </summary>
- public static readonly DependencyProperty CollapsedSizeProperty =
- DependencyProperty.Register("CollapsedSize", typeof(double), typeof(Transition), new PropertyMetadata(default(double), OnIsShowChanged));
-
- /// <summary>
- /// 折叠后的大小
- /// </summary>
- public double CollapsedSize
- {
- get { return (double)GetValue(CollapsedSizeProperty); }
- set { SetValue(CollapsedSizeProperty, value); }
- }
-
- #endregion 依赖属性
-
- /// <summary>
- /// 关闭转换器
- /// </summary>
- /// <returns>关闭是否完成</returns>
- public async Task<bool> Close()
- {
- var taskCompletionSource = new TaskCompletionSource<bool>();
- this.Closed += (a, b) => taskCompletionSource.TrySetResult(true);
- return await taskCompletionSource.Task;
- }
-
- private static void OnIsShowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var transition = d as Transition;
- ChangeTransitionVisual(transition);
- }
-
- private static void ChangeTransitionVisual(Transition transition)
- {
- if (transition.IsLoaded && transition.Type != TransitionType.None)
- {
- if (transition.IsShow)
- {
- ShowAnimation(transition);
- }
- else
- {
- CloseAnimation(transition);
- }
- }
- else if (transition.IsInitialized || transition.Type == TransitionType.None)
- {
- transition.BeginAnimation(Transition.ProgressProperty, null);
-
- if (transition.IsShow)
- {
- transition.Progress = 1;
- }
- else
- {
- transition.Progress = 0;
- }
- }
- }
-
- /// <summary>
- /// 开始显示动画
- /// </summary>
- /// <param name="transition">转换</param>
- public static void ShowAnimation(Transition transition)
- {
- if (transition.Type == TransitionType.None)
- {
- return;
- }
-
- Storyboard storyboard = new Storyboard();
- storyboard.Completed += (sender, e) =>
- {
- var args = new RoutedEventArgs();
- args.RoutedEvent = Transition.ShowedEvent;
- transition.RaiseEvent(args);
- transition.ShowedCommand?.Execute(null);
- };
-
- DoubleAnimation progressAnimation;
- if (transition.Type >= TransitionType.CollapseUp && transition.Type <= TransitionType.CollapseRight)
- {
- progressAnimation = GetProgressAnimation(transition, 1, transition.ShowEasingFunction);
- }
- else
- {
- progressAnimation = GetProgressAnimation(transition, 1, transition.ShowEasingFunction, from: 0);
- }
-
- switch (transition.Type)
- {
- case TransitionType.Fade:
- case TransitionType.CollapseUp:
- case TransitionType.CollapseDown:
- case TransitionType.CollapseLeft:
- case TransitionType.CollapseRight:
- default:
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeLeft:
- DoubleAnimation translateAnimation = GetTranslateXAnimation(transition, transition.Offset, 0, transition.ShowEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeRight:
- translateAnimation = GetTranslateXAnimation(transition, -transition.Offset, 0, transition.ShowEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeUp:
- translateAnimation = GetTranslateYAnimation(transition, transition.Offset, 0, transition.ShowEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeDown:
- translateAnimation = GetTranslateYAnimation(transition, -transition.Offset, 0, transition.ShowEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.Zoom:
- DoubleAnimation scaleXAnimation = GetScaleXAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- DoubleAnimation scaleYAnimation = GetScaleYAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomX:
- scaleXAnimation = GetScaleXAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomY:
- scaleYAnimation = GetScaleYAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomLeft:
- transition.RenderTransformOrigin = new Point(0, 0.5);
- scaleXAnimation = GetScaleXAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomRight:
- transition.RenderTransformOrigin = new Point(1, 0.5);
- scaleXAnimation = GetScaleXAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomUp:
- transition.RenderTransformOrigin = new Point(0.5, 0);
- scaleYAnimation = GetScaleYAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomDown:
- transition.RenderTransformOrigin = new Point(0.5, 1);
- scaleYAnimation = GetScaleYAnimation(transition, transition.InitialScale, 1, transition.ShowEasingFunction);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
- }
-
- storyboard.Begin();
- }
-
- /// <summary>
- /// 开始关闭动画
- /// </summary>
- /// <param name="transition">转换</param>
- public static void CloseAnimation(Transition transition)
- {
- if (transition.Type == TransitionType.None)
- {
- return;
- }
-
- Storyboard storyboard = new Storyboard();
- storyboard.Completed += (sender, e) =>
- {
- var args = new RoutedEventArgs();
- args.RoutedEvent = Transition.ClosedEvent;
- transition.RaiseEvent(args);
- transition.ClosedCommand?.Execute(null);
- };
-
- DoubleAnimation progressAnimation;
- if (transition.Type >= TransitionType.CollapseUp && transition.Type <= TransitionType.CollapseRight)
- {
- var progress = GetCollapsedProgress(transition);
- progressAnimation = GetProgressAnimation(transition, progress, transition.CloseEasingFunction);
- }
- else
- {
- progressAnimation = GetProgressAnimation(transition, 0, transition.CloseEasingFunction, from: 1);
- }
-
- switch (transition.Type)
- {
- case TransitionType.Fade:
- case TransitionType.CollapseUp:
- case TransitionType.CollapseDown:
- case TransitionType.CollapseLeft:
- case TransitionType.CollapseRight:
- default:
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeLeft:
- DoubleAnimation translateAnimation = GetTranslateXAnimation(transition, 0, transition.Offset, transition.CloseEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeRight:
- translateAnimation = GetTranslateXAnimation(transition, 0, -transition.Offset, transition.CloseEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeUp:
- translateAnimation = GetTranslateYAnimation(transition, 0, transition.Offset, transition.CloseEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.FadeDown:
- translateAnimation = GetTranslateYAnimation(transition, 0, -transition.Offset, transition.CloseEasingFunction);
- storyboard.Children.Add(translateAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.Zoom:
- DoubleAnimation scaleXAnimation = GetScaleXAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- DoubleAnimation scaleYAnimation = GetScaleYAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomX:
- scaleXAnimation = GetScaleXAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomY:
- scaleYAnimation = GetScaleYAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomLeft:
- transition.RenderTransformOrigin = new Point(0, 0.5);
- scaleXAnimation = GetScaleXAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomRight:
- transition.RenderTransformOrigin = new Point(1, 0.5);
- scaleXAnimation = GetScaleXAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- storyboard.Children.Add(scaleXAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomUp:
- transition.RenderTransformOrigin = new Point(0.5, 0);
- scaleYAnimation = GetScaleYAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
-
- case TransitionType.ZoomDown:
- transition.RenderTransformOrigin = new Point(0.5, 1);
- scaleYAnimation = GetScaleYAnimation(transition, 1, transition.InitialScale, transition.CloseEasingFunction);
- storyboard.Children.Add(scaleYAnimation);
- storyboard.Children.Add(progressAnimation);
- break;
- }
-
- storyboard.Begin();
- }
-
- private static DoubleAnimation GetProgressAnimation(Transition transition, double to, IEasingFunction easing, double? from = null)
- {
- DoubleAnimation progressAnimation = new DoubleAnimation()
- {
- From = transition.Progress == to ? (to > 0 ? 0 : 1) : from,
- To = to,
- Duration = transition.Duration,
- EasingFunction = easing,
- };
-
- if (from != null)
- {
- progressAnimation.From = from;
- }
-
- Storyboard.SetTargetProperty(progressAnimation, new PropertyPath(ProgressProperty));
- Storyboard.SetTarget(progressAnimation, transition);
-
- return progressAnimation;
- }
-
- private static DoubleAnimation GetTranslateXAnimation(Transition transition, double from, double to, IEasingFunction easing)
- {
- DoubleAnimation transformAnimation = new DoubleAnimation()
- {
- From = from,
- To = to,
- Duration = transition.Duration,
- EasingFunction = easing,
- };
-
- Storyboard.SetTargetProperty(transformAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));
- Storyboard.SetTarget(transformAnimation, transition);
- return transformAnimation;
- }
-
- private static DoubleAnimation GetTranslateYAnimation(Transition transition, double from, double to, IEasingFunction easing)
- {
- DoubleAnimation transformAnimation = new DoubleAnimation()
- {
- From = from,
- To = to,
- Duration = transition.Duration,
- EasingFunction = easing,
- };
-
- Storyboard.SetTargetProperty(transformAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"));
- Storyboard.SetTarget(transformAnimation, transition);
- return transformAnimation;
- }
-
- private static DoubleAnimation GetScaleXAnimation(Transition transition, double from, double to, IEasingFunction easing)
- {
- DoubleAnimation transformAnimation = new DoubleAnimation()
- {
- From = from,
- To = to,
- Duration = transition.Duration,
- EasingFunction = easing,
- };
-
- Storyboard.SetTargetProperty(transformAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
- Storyboard.SetTarget(transformAnimation, transition);
- return transformAnimation;
- }
-
- private static DoubleAnimation GetScaleYAnimation(Transition transition, double from, double to, IEasingFunction easing)
- {
- DoubleAnimation transformAnimation = new DoubleAnimation()
- {
- From = from,
- To = to,
- Duration = transition.Duration,
- EasingFunction = easing,
- };
-
- Storyboard.SetTargetProperty(transformAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
- Storyboard.SetTarget(transformAnimation, transition);
- return transformAnimation;
- }
-
- private static double GetCollapsedProgress(Transition transition)
- {
- switch (transition.Type)
- {
- case TransitionType.CollapseUp:
- case TransitionType.CollapseDown:
- return transition.ActualHeight == 0 ? 0 : transition.CollapsedSize / transition.ActualHeight;
-
- case TransitionType.CollapseLeft:
- case TransitionType.CollapseRight:
- return transition.ActualWidth == 0 ? 0 : transition.CollapsedSize / transition.ActualWidth;
-
- default:
- return 0;
- }
- }
- }
-
- /// <summary>
- /// 转换类型
- /// </summary>
- public enum TransitionType
- {
- /// <summary>
- /// 无
- /// </summary>
- None = 0,
-
- /// <summary>
- /// 淡入
- /// </summary>
- Fade,
-
- /// <summary>
- /// 向左淡入
- /// </summary>
- FadeLeft,
-
- /// <summary>
- /// 向右淡入
- /// </summary>
- FadeRight,
-
- /// <summary>
- /// 向上淡入
- /// </summary>
- FadeUp,
-
- /// <summary>
- /// 向下淡入
- /// </summary>
- FadeDown,
-
- /// <summary>
- /// 缩放
- /// </summary>
- Zoom,
-
- /// <summary>
- /// X 轴缩放
- /// </summary>
- ZoomX,
-
- /// <summary>
- /// Y 轴缩放
- /// </summary>
- ZoomY,
-
- /// <summary>
- /// 向左缩放
- /// </summary>
- ZoomLeft,
-
- /// <summary>
- /// 向右缩放
- /// </summary>
- ZoomRight,
-
- /// <summary>
- /// 向上缩放
- /// </summary>
- ZoomUp,
-
- /// <summary>
- /// 向下缩放
- /// </summary>
- ZoomDown,
-
- /// <summary>
- /// 向上折叠
- /// </summary>
- CollapseUp,
-
- /// <summary>
- /// 向下折叠
- /// </summary>
- CollapseDown,
-
- /// <summary>
- /// 向左折叠
- /// </summary>
- CollapseLeft,
-
- /// <summary>
- /// 向右折叠
- /// </summary>
- CollapseRight,
- }
- }
|