WPF与缓动(一) N次缓动

简介: 原文:WPF与缓动(一) N次缓动                                                             WPF与缓动(一)  N次缓动                                                         ...
原文: WPF与缓动(一) N次缓动

                                                             WPF与缓动(一)  N次缓动
                                                                                       周银辉

如果我们希望制作的动画效果像现实生活中的运动一样平滑, 比如汽车的启动与停止总有一个加速或减速的过程, 那么我们有必要研究一下"缓动"

缓入: 速度逐渐增加的过程,比如汽车的启动
如果我们用曲线上的点的斜率表示速度,那么在数学上它对应了下面这样的曲线:
easeIn.PNG
缓出:速度逐渐减小的过程,比如汽车的停止
在数学上它对应了下面的曲线
easeOut.PNG
就加速运动而言,  根据以下位置与加速度等公式
formula2.PNG
我们可以得到,任意时刻的速度等于总的路程乘以当前时间与总时间的比值的平方, 而总的路程实际将相当与WPF中Animation的To与From的差值, 当前时间与总时间的比值实际上相当与WPF中animationClock.CurrentProgress.Value值.
除此之外,我们发现,曲线的指数越大,点的斜率变化越快,那么加速度也就越大.
有了这些知识,我们可以很好的模拟加速运动了
参考以下代码

img_a6339ee3e57d1d52bc7d02b338e15a60.gif using  System;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
using  System.Collections.Generic;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
using  System.Text;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
using  System.Windows.Media.Animation;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
using  System.Windows;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
namespace  EaseMoveDemo
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif {
img_33d02437d135341f0800e3d415312ae8.gif    
public class EaseMoveAnimation : DoubleAnimationBase
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
public static readonly DependencyProperty FromProperty = DependencyProperty.Register(
img_33d02437d135341f0800e3d415312ae8.gif            
"From", typeof(double?), typeof(EaseMoveAnimation), new PropertyMetadata(null));
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
public static readonly DependencyProperty ToProperty = DependencyProperty.Register(
img_33d02437d135341f0800e3d415312ae8.gif            
"To", typeof(double?), typeof(EaseMoveAnimation), new PropertyMetadata(null));
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
public static readonly DependencyProperty PowerProperty = DependencyProperty.Register(
img_33d02437d135341f0800e3d415312ae8.gif            
"Power", typeof(double?), typeof(EaseMoveAnimation), new PropertyMetadata(null));
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
public double? From
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
get
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
return (double?)this.GetValue(EaseMoveAnimation.FromProperty);
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_33d02437d135341f0800e3d415312ae8.gif            
set
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
this.SetValue(EaseMoveAnimation.FromProperty, value);
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
public double? To
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
get
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
return (double?)this.GetValue(EaseMoveAnimation.ToProperty);
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_33d02437d135341f0800e3d415312ae8.gif            
set
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
this.SetValue(EaseMoveAnimation.ToProperty, value);
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_33d02437d135341f0800e3d415312ae8.gif
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
/**//// <summary>
img_33d02437d135341f0800e3d415312ae8.gif        
/// 幂指数,值越大,曲线上点的斜率越大,加速度越大,设置为5时效果较好
img_105a1e124122b2abcee4ea8e9f5108f3.gif        
/// </summary>

img_33d02437d135341f0800e3d415312ae8.gif        public double? Power
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
get
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
return (double?)this.GetValue(EaseMoveAnimation.PowerProperty);
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_33d02437d135341f0800e3d415312ae8.gif            
set
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
this.SetValue(EaseMoveAnimation.PowerProperty, value);
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue, AnimationClock animationClock)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
double from = (this.From==null?defaultDestinationValue:(double)this.From);
img_33d02437d135341f0800e3d415312ae8.gif            
double to = (this.To==null?defaultOriginValue:(double)this.To);
img_33d02437d135341f0800e3d415312ae8.gif            
double delta = to - from;
img_33d02437d135341f0800e3d415312ae8.gif            
double power = this.Power == null ? 2 : (double)this.Power;
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif            
//加速
img_33d02437d135341f0800e3d415312ae8.gif
            return delta * Math.Pow(animationClock.CurrentProgress.Value, power) + from;
img_33d02437d135341f0800e3d415312ae8.gif            
//return delta * Math.Pow(animationClock.CurrentProgress.Value, 1/power) + from;
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif            
//先加速后减速
img_33d02437d135341f0800e3d415312ae8.gif            
//if (animationClock.CurrentProgress.Value < 0.5)
img_33d02437d135341f0800e3d415312ae8.gif            
//{
img_33d02437d135341f0800e3d415312ae8.gif            
//    return delta / 2 * Math.Pow(animationClock.CurrentProgress.Value * 2, power) + from;
img_33d02437d135341f0800e3d415312ae8.gif            
//}
img_33d02437d135341f0800e3d415312ae8.gif            
//return delta / 2 * Math.Pow((animationClock.CurrentProgress.Value - 0.5) * 2, 1/power) + delta / 2 + from;
img_105a1e124122b2abcee4ea8e9f5108f3.gif
        }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
protected override System.Windows.Freezable CreateInstanceCore()
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
return new EaseMoveAnimation();
img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_105a1e124122b2abcee4ea8e9f5108f3.gif    }

img_05dd8d549cff04457a6366b0a7c9352a.gif}

img_a6339ee3e57d1d52bc7d02b338e15a60.gif


下载源代码



目录
相关文章
|
C#
WPF与缓动(三) 指数缓动
原文:WPF与缓动(三) 指数缓动                                                         WPF与缓动(三) 指数缓动                                                                             周银辉指数缓动给人的感觉是加速度很大.
772 2
|
C#
WPF与缓动(二) 正弦与余弦缓动
原文:WPF与缓动(二) 正弦与余弦缓动                                                                            WPF与缓动(二) 正弦与余弦缓动                                     ...
978 0
|
C#
WPF与缓动(四) 弧形缓动
原文:WPF与缓动(四) 弧形缓动                                                   WPF与缓动(四)  弧形缓动                                                                   ...
834 1
|
C# 内存技术
WPF中ListBox滚动时的缓动效果
原文:WPF中ListBox滚动时的缓动效果 上周工作中遇到的问题: 常规的ListBox在滚动时总是一格格的移动,感觉上很生硬。
1449 0
|
C#
WPF中的动画——(四)缓动函数
原文:WPF中的动画——(四)缓动函数 缓动函数可以通过一系列公式模拟一些物理效果,如实地弹跳或其行为如同在弹簧上一样。它们一般应用在From/To/By动画上,可以使得其动画更加平滑。     var widthAnimation = new DoubleAnimation()    {    ...
1197 0
|
C# 内存技术
WPF界面设计技巧(7)—模拟电梯升降的缓动动画
原文:WPF界面设计技巧(7)—模拟电梯升降的缓动动画     如同Flash一样,WPF的亮点之一也在于其擅于表现平滑的动画效果,但以移动动画来说,仅凭简单的起始位置、目标位置,所产生的动画仍会非常生硬,这种动画忽略了移动开始时的加速过程与移动结束时的减速过程。
1258 0
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
579 1
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
1620 0
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件