最近用画布的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. AGC015D题解

    简要题意 给定一个区间 \([l,r]\),从中选出若干整数按位或,求可能出现的数的方案数. 数据范围:\(1\le l\le r\le2^{60}\). 思路 首先对于 \([l,r]\) 里的数全 ...

  2. Chrome 133 里程碑式更新 - moveBefore, 或开启前端框架未来新纪元?

    相关背景: Chrome 133 版本(将于 2 月 4 日发布稳定版)引入了一个新的 DOM 操作方法:Node.prototype.moveBefore.这一方法虽然看似简单,但其意义重大,因为它 ...

  3. 学习理论:单阶段代理损失的(H, R) - 一致界证明

    1 导引 我们在上一篇博客<学习理论:预测器-拒绝器多分类弃权学习>中介绍了弃权学习的基本概念和方法,其中包括了下列针对多分类问题的单阶段预测器-拒绝器弃权损失\(L_{\text{abs ...

  4. DeepSeek过时了?全网刷屏的Manus到底是什么?这样写申请秒过审核

    1.Manus是什么? Manus的官网地址:https://manus.im/ Manus是一个通用AI智能体,它连接思维与行动:它不仅思考,还能交付成果. 2. Manus能做什么? 最近几天,M ...

  5. github520cli解决无法github访问问题

    github并没有被GFW直接墙掉,而是因为DNS污染导致经常无法访问 访问的时候经常出现push或者pull代码的时间很长,出现无法访问仓库,请检查是否有权限的报错,这可能就是被DNS污染了 如何解 ...

  6. 【Azure Fabric Service】演示使用PowerShell命令部署SF应用程序(.NET)

    问题描述 在中国区微软云Azure上使用Service Fabrics服务,本地通过Visual Studio 2022的发布.NET应用,发现无法发布! 在搜寻官方文档之后,可以通过PowerShe ...

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

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

  8. python web服务器--WSGI/ASGI协议--web框架,三者之间的关系

    在 Python Web 开发中,Web 服务器.WSGI/ASGI 协议 和 Web 框架 是三个核心组成部分,它们共同协作以实现完整的 Web 应用程序.以下是三者之间的关系和作用的详细讲解: 1 ...

  9. static修饰成员方法、static修饰成员的特点总结、浅聊主方法-java se进阶 day01

    1.工具类的介绍 工具类不是用于描述事物的类,而是帮我们完成事情的类(打工) 如图 当我们编写完这个类后,我们会发现一件事,这个类自己本身并没有意义,这个类完全是给用户进行调用方法的 既然是专门给用户 ...

  10. 【Linux】3.9 网络配置

    网络配置 1 Linux网络配置原理 虚拟机NAT网络配置原理 2 查看网络IP和网关 2.1 虚拟机网络编辑器 2.2 修改IP地址 2.3 查看网关 2.4 查看windows中的虚拟网卡的ip地 ...