1. 程式人生 > 其它 >自定義Marix的自定義動畫,支援緩動動畫屬性

自定義Marix的自定義動畫,支援緩動動畫屬性

最近用畫布的MatrixTransForm做變換,需要用Matrix做動畫處理,網上衝浪找了一圈,沒有找出好的解決方法

Stack Overflow給出了一部分的解決方法,但是不支援緩動函式,貌似不是最優的:wpf - Smooth animation using MatrixTransform? - Stack Overflow

小組的大牛給了一個最新的,支援 IEasingFunction 屬性的 關於 Matrix的動畫,完美解決

1、LinearMatrixAnimation 主呼叫方法

 public class LinearMatrixAnimation : LinearMatrixAnimationBase
    {
        
#region Fields private Matrix[] _keyValues; private AnimationType _animationType; private bool _isAnimationFunctionValid; private static Type typeofProp = typeof(Matrix?); private static Type typeofThis = typeof(LinearMatrixAnimation); #endregion #region
Dependency Properties public static readonly DependencyProperty FromProperty = DependencyProperty.Register("From", typeofProp, typeofThis, new PropertyMetadata(null, AnimationFunction_Changed), ValidateFromToOrByValue); public static readonly DependencyProperty ToProperty = DependencyProperty.Register(
"To", typeofProp, typeofThis, new PropertyMetadata(null, AnimationFunction_Changed), ValidateFromToOrByValue); public static readonly DependencyProperty EasingFunctionProperty = DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeofThis); public Matrix? From { get { return (Matrix?)GetValue(FromProperty); } set { SetValue(FromProperty, value); } } public Matrix? To { get { return (Matrix?)GetValue(ToProperty); } set { SetValue(ToProperty, value); } } public IEasingFunction EasingFunction { get { return (IEasingFunction)GetValue(EasingFunctionProperty); } set { SetValue(EasingFunctionProperty, value); } } #endregion #region Constructors /// <summary> /// Static ctor for LinearMatrixAnimation establishes /// dependency properties, using as much shared data as possible. /// </summary> static LinearMatrixAnimation() { } public LinearMatrixAnimation() : base() { } public LinearMatrixAnimation(Matrix toValue, Duration duration) : this() { To = toValue; Duration = duration; } public LinearMatrixAnimation(Matrix toValue, Duration duration, FillBehavior fillBehavior) : this() { To = toValue; Duration = duration; FillBehavior = fillBehavior; } public LinearMatrixAnimation(Matrix fromValue, Matrix toValue, Duration duration) : this() { From = fromValue; To = toValue; Duration = duration; } public LinearMatrixAnimation(Matrix fromValue, Matrix toValue, Duration duration, FillBehavior fillBehavior) : this() { From = fromValue; To = toValue; Duration = duration; FillBehavior = fillBehavior; } #endregion #region Private Methods private static void AnimationFunction_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { LinearMatrixAnimation a = (LinearMatrixAnimation)d; a._isAnimationFunctionValid = false; } private static bool ValidateFromToOrByValue(object value) { return true;//不做校驗 } private void ValidateAnimationFunction() { _animationType = AnimationType.Automatic; _keyValues = null; if (From.HasValue) { if (To.HasValue) { _animationType = AnimationType.FromTo; _keyValues = new Matrix[2]; _keyValues[0] = From.Value; _keyValues[1] = To.Value; } else { _animationType = AnimationType.From; _keyValues = new Matrix[1]; _keyValues[0] = From.Value; } } else if (To.HasValue) { _animationType = AnimationType.To; _keyValues = new Matrix[1]; _keyValues[0] = To.Value; } _isAnimationFunctionValid = true; } #endregion #region Protected Methods protected override Freezable CreateInstanceCore() { return new LinearMatrixAnimation(); } protected override Matrix GetCurrentValueCore(Matrix defaultOriginValue, Matrix defaultDestinationValue, AnimationClock animationClock) { Debug.Assert(animationClock.CurrentState != ClockState.Stopped); if (!_isAnimationFunctionValid) { ValidateAnimationFunction(); } double progress = animationClock.CurrentProgress.Value; IEasingFunction easingFunction = EasingFunction; if (easingFunction != null) { progress = easingFunction.Ease(progress); } Matrix from = new Matrix(); Matrix to = new Matrix(); switch (_animationType) { case AnimationType.Automatic: from = defaultOriginValue; to = defaultDestinationValue; break; case AnimationType.From: from = _keyValues[0]; to = defaultDestinationValue; break; case AnimationType.To: from = defaultOriginValue; to = _keyValues[0]; break; case AnimationType.FromTo: from = _keyValues[0]; to = _keyValues[1]; break; default: Debug.Fail("Unknown animation type."); break; } if (To.HasValue) { Matrix newMatrix = from.Add(to.Subtract(from).Multiply(progress)); return newMatrix; } return Matrix.Identity; } #endregion #region Public Methods public new LinearMatrixAnimation Clone() { return (LinearMatrixAnimation)base.Clone(); } #endregion }

2、動畫型別:

 /// <summary>
    /// Describes the behavior of an animation.
    /// </summary>
    internal enum AnimationType : byte
    {
        /// <summary>
        /// The animation animates from the defaultOriginValue value to the defaultDestinationValue.
        /// </summary>
        Automatic = 0,

        /// <summary>
        /// The animation animates from the From property value to the defaultDestinationValue.
        /// </summary>
        From,

        /// <summary>
        /// The animation animates from the defaultOriginValue to the To property value.
        /// </summary>
        To,

        /// <summary>
        /// The animation animates from the defaultOriginValue value to the defaultOriginValue value plus
        /// the By property value.
        /// </summary>
        By,

        /// <summary>
        /// The animation animates from the From property value to the To property value.
        /// </summary>
        FromTo,

        /// <summary>
        /// The animation animates from the From property value to the From property value plus
        /// the By property value.
        /// </summary>
        FromBy
    }

3、LinearMatrixAnimationBase 基類實現:

 public abstract class LinearMatrixAnimationBase : AnimationTimeline
    {
        #region Constructors

        /// <Summary>
        /// Creates a new DoubleAnimationBase.
        /// </Summary>
        protected LinearMatrixAnimationBase()
            : base()
        {
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates a copy of this LinearMatrixAnimationBase
        /// </summary>
        /// <returns>The copy</returns>
        public new LinearMatrixAnimationBase Clone()
        {
            return (LinearMatrixAnimationBase)base.Clone();
        }

        /// <summary>
        /// Calculates the value this animation believes should be the current value for the property.
        /// </summary>
        public override sealed object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
        {
            if (defaultOriginValue == null)
            {
                throw new ArgumentNullException("defaultOriginValue");
            }
            if (defaultDestinationValue == null)
            {
                throw new ArgumentNullException("defaultDestinationValue");
            }
            return GetCurrentValue((Matrix)defaultOriginValue, (Matrix)defaultDestinationValue, animationClock);
        }

        /// <summary>
        /// Returns the type of the target property
        /// </summary>
        public override sealed Type TargetPropertyType
        {
            get
            {
                ReadPreamble();

                return typeof(Matrix);
            }
        }

        /// <summary>
        /// Calculates the value this animation believes should be the current value for the property.
        /// </summary>
        public Matrix GetCurrentValue(Matrix defaultOriginValue, Matrix defaultDestinationValue, AnimationClock animationClock)
        {
            ReadPreamble();

            if (animationClock == null)
            {
                throw new ArgumentNullException("animationClock");
            }

            if (animationClock.CurrentState == ClockState.Stopped)
            {
                return defaultDestinationValue;
            }

            return GetCurrentValueCore(defaultOriginValue, defaultDestinationValue, animationClock);
        }

        protected abstract Matrix GetCurrentValueCore(Matrix defaultOriginValue, Matrix defaultDestinationValue, AnimationClock animationClock);

        #endregion
    }

4、自定義幫助類

public static class MatrixHelper
    {
        public static Matrix Add(this Matrix left, Matrix right)
        {
            double m11 = left.M11 + right.M11;
            double m12 = left.M12 + right.M12;
            double m21 = left.M21 + right.M21;
            double m22 = left.M22 + right.M22;
            double offsetX = left.OffsetX + right.OffsetX;
            double offsetY = left.OffsetY + right.OffsetY;
            Matrix newMatrix = new Matrix(m11, m12,
                m21, m22,
                offsetX, offsetY);
            return newMatrix;
        }

        public static Matrix Subtract(this Matrix left, Matrix right)
        {
            double m11 = left.M11 - right.M11;
            double m12 = left.M12 - right.M12;
            double m21 = left.M21 - right.M21;
            double m22 = left.M22 - right.M22;
            double offsetX = left.OffsetX - right.OffsetX;
            double offsetY = left.OffsetY - right.OffsetY;
            Matrix newMatrix = new Matrix(m11, m12,
                m21, m22,
                offsetX, offsetY);
            return newMatrix;
        }

        public static Matrix Multiply(this Matrix matrix, double factor)
        {
            double m11 = matrix.M11 * factor;
            double m12 = matrix.M12 * factor;
            double m21 = matrix.M21 * factor;
            double m22 = matrix.M22 * factor;
            double offsetX = matrix.OffsetX * factor;
            double offsetY = matrix.OffsetY * factor;
            Matrix newMatrix = new Matrix(m11, m12,
                m21, m22,
                offsetX, offsetY);
            return newMatrix;
        }
    }

方法呼叫:

var  _lineAnimation = new LinearMatrixAnimation()
            {
                Duration = TimeSpan.FromSeconds(0.3),
                FillBehavior = FillBehavior.Stop,
                EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseInOut }
            };

  _lineAnimation.From = Matrix;
  _lineAnimation.To = _animationMatrix;
            _matrixTransform.BeginAnimation(MatrixTransform.MatrixProperty, _lineAnimation);

呼叫的效果: