最近用画布的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. Spark 广播变量(broadcast)更新方法

    Spark 广播变量(broadcast)更新方法更新方法spark 广播变量可以通过unpersist方法删除,然后重新广播 val map = sc.textFile("/test.tx ...

  2. AI回答(deepseek):vue3制作手机屏网站

    使用 Vue 3 制作一个适合手机屏幕的网站(移动端网站)是一个非常常见的需求.以下是一个完整的指南,帮助你从零开始构建一个移动端优化的 Vue 3 项目. 1. 创建 Vue 3 项目 使用 Vit ...

  3. manim边学边做--向量相关的场景类

    VectorScene是Manim动画库中专门用于向量空间可视化的场景类,继承自基础 Scene 类. 它通过封装一系列向量操作方法,使数学教育.物理模拟等领域的动画制作更加高效. 本文主要介绍Vec ...

  4. 张高兴的大模型开发实战:(二)使用 LangChain 构建本地知识库应用

    目录 基础概念 什么是 LangChain 什么是 Ollama 环境搭建与配置 安装 Ollama 安装 LangChain 文档加载 加载 JSON 数据 加载文件夹中的文档 文本向量化 实现问答 ...

  5. 软件测试_Fiddler抓包工具

    多数资料摘抄至 https://www.cnblogs.com/miantest/p/7289694.html 一.在 macOS 下如何安装 (https://www.telerik.com/fid ...

  6. CompletableFuture你真的懂了么,我劝你在项目中慎用

    1. 前言 在实际做项目中,我们经常使用多线程.异步的来帮我们做一些事情. 比如用户抽取奖品,异步的给他发一个push. 又比如一段前后不相关的业务逻辑,原本是顺序执行,耗时=(A + B + C), ...

  7. 大型通用电子制造执行系统(MES)

    ​ 简介: 系统参考西门子MOM智能制造Opcenter工业软件制造执行系统Camstar电子套件人机料法环数据建模业务对象和车间生产执行事务逻辑,采用面向对象分层设计与C#编程开发:包含电子制造企业 ...

  8. Mac 刷题环境配置

    Mac 刷题环境配置 这篇博文主要记录自己为了更方便的在 Mac 上写算法题,主要是基于 Clion做的一些环境配置:有些操作其实在 Windows ,Linux 下也是通用的,如果看到的小伙伴也可以 ...

  9. ASP.NET 日志路径

    默认路径 protected void Button_StreamWrite_Click(object sender, EventArgs e) {     StreamWriter sw = new ...

  10. nginx中的路径匹配规则详解(location规则)

    Nginx的路径匹配规则 Nginx的匹配规则用location指令来实现,Nginx 的location指令用于匹配请求的 URI(请求路径),并根据匹配结果执行特定的处理指令.location是实 ...