最近用画布的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);

调用的效果:

自定义Marix的自定义动画,支持缓动动画属性的更多相关文章

  1. jQuery-1.9.1源码分析系列(十五) 动画处理——缓动动画核心Tween

    在jQuery内部函数Animation中调用到了createTweens()来创建缓动动画组,创建完成后的结果为: 可以看到上面的缓动动画组有四个原子动画组成.每一个原子动画的信息都包含在里面了. ...

  2. js简单动画:匀速动画、缓动动画、多物体动画以及透明度动画

    主要实现以下几种简单的动画效果(其实原理基本相同): 1.匀速动画:物体的速度固定 2.缓动动画:物体速度逐渐变慢 3.多物体动画 4.透明度动画 效果实现: 1.匀速动画(以物体左右匀速运动为例) ...

  3. js off 缓动动画

    动画也有很多种,一起来学习,缓动动画吧 缓动动画 1.缓动动画原理=盒子位置+(目标盒子位置-现在盒子位置)/10 2.步长越来越小 3.让步长越来越小的公式      步长=(目标位置-本身位置)/ ...

  4. 背水一战 Windows 10 (15) - 动画: 缓动动画

    [源码下载] 背水一战 Windows 10 (15) - 动画: 缓动动画 作者:webabcd 介绍背水一战 Windows 10 之 动画 缓动动画 - easing 示例演示缓动(easing ...

  5. 重新想象 Windows 8 Store Apps (19) - 动画: 线性动画, 关键帧动画, 缓动动画

    原文:重新想象 Windows 8 Store Apps (19) - 动画: 线性动画, 关键帧动画, 缓动动画 [源码下载] 重新想象 Windows 8 Store Apps (19) - 动画 ...

  6. WPF界面设计技巧(7)—模拟电梯升降的缓动动画

    原文:WPF界面设计技巧(7)-模拟电梯升降的缓动动画 如同Flash一样,WPF的亮点之一也在于其擅于表现平滑的动画效果,但以移动动画来说,仅凭简单的起始位置.目标位置,所产生的动画仍会非常生硬,这 ...

  7. Windows Phone开发(42):缓动动画

    原文:Windows Phone开发(42):缓动动画 前面在讨论关键帧动画的时候,我有意把几个带缓动动画的关键帧动画忽略掉,如EasingColorKeyFrame.EasingDoubleKeyF ...

  8. JS基础知识——缓动动画

    基于距离的缓动动画 原理:设定起始位置  start 和终止位置 end,变化会越来越慢. 公式:start=start+(end-start)/10;     这个10不是固定的,想分成多少份就分成 ...

  9. JS-特效 ~ 04. client对象、网页可视区域的宽高、client / offset / scroll 三大家族的区别、冒泡事件、事件委托、获取内嵌式和外链式属性getStyle(ele,attr) ;、缓动动画封装

    知识点: 模拟滚动条的解除事件问题 : event内置对象,包含 了大量事件: page兼容性: pageX || clientX + scool().top  : if (true === a)tr ...

  10. c# Winform 缓动动画

    一.定义缓动动画类public class AnimationHelper { Timer animationTimer = new Timer(); double velocity = 0.0; P ...

随机推荐

  1. Archlinux 更新失败之驱动与 Xorg 配置错误

    Archlinux系统更新是滚动更新,所以更新失败又被叫做"滚挂了" 此次滚挂发生在1月27日,过了那么久了才想起来该记录了-- 现象 滚挂的现象是,能够进系统,但是笔记本电脑自带 ...

  2. 将DeepSeek接入人类大脑会怎样??

    昨天在与同事聊起最近大火的DeepSeek, 突然,有一个不切实际的想法,如果DeepSeek或人工智能AI能以某种形式接入人类大脑, 比如,通过芯片不侵入式连接大脑 或者 外带什么眼镜. 隐形眼镜之 ...

  3. DeepSeek满血版测试

    技术背景 很多厂商以次充好,用蒸馏版DeepSeek冒充满血版.本文提供一些收集的问题集,可以用于测试是否满血DeepSeek.经过实际测试,国内厂商中只有满血版DeepSeek可以全对.但是各厂商后 ...

  4. 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理

    在 AI 编程领域国内外有一堆能叫的上号的应用: Cursor Windsurf Trae 阿里的「通义灵码」 百度的「文心快码」 字节跳动的「MarsCode」 科大讯飞的「iFlyCode」 Gi ...

  5. ocr识别过程中报错 tesseract is not installed

    这个问题无论在初始编译时或者在后来坏境变更调试时都会遇到的问题. 解决:问题原因是源码中的默认路径位置与文件位置不同,需要更改一下

  6. mongodb关机重启

    正确关闭 mongodb 查看 mongodb 进程 ps -ef | grep mongodb # 或者 ps -aux | grep mongodb 杀掉 mongodb 进程(不推荐) kill ...

  7. Netty源码—2.Reactor线程模型一

    大纲 1.关于NioEventLoop的问题整理 2.理解Reactor线程模型主要分三部分 3.NioEventLoop的创建 4.NioEventLoop的启动 1.关于NioEventLoop的 ...

  8. Delphi DataModule1 FDConnection1数据库连接

    procedure Tdm.DataModuleCreate(Sender: TObject); begin try FDConnection1.Connected := False; FDConne ...

  9. Delphi 禁止重复运行程序的方法

    第一种方法,使用"过程调用" procedure Del; // 自定义过程 var Mutex: THandle; begin Mutex := CreateMutex(nil, ...

  10. Momentum Contrast for Unsupervised Visual Representation Learning论文精读

    目录 Birth of MoCo Supervised Learning Contrastive Learning MoCo Dictionary Limits of the early learni ...