日常经常能看到缓入缓出的动画效果,如:

1,带缓入缓出效果的滚动条:

2,带缓入缓出效果的呼吸灯:

像上面这种效果,就是用到了三角函数相关的知识,下面将从头开始一步步去讲解如何实现这种效果。


一、基础知识

(一)三角函数

常用的三角函数有正弦函数(sin)、余弦函数(cos)、正切函数(tan)。在动画效果中常用的是正弦函数和余弦函数,由于两者可以互相转化,所以本文将以正弦函数来进行讲解。

如下图所示直角三角形ABC:

则:

sin(A)=a/c

即:角A的正弦值=角A的对边/斜边

(二)正弦曲线

将三角函数与动画桥接起来的便是三角函数曲线。

以正弦函数为例,其正弦曲线公式为:y = A*sin(B*x + C) + D

其中y、x分别是纵坐标、横坐标。

1,在默认状态时,即:y=sin(x) 时,其曲线如下图所示:

2,正弦曲线公式中的参数 “A” 控制曲线的振幅,A 值越大,振幅越大,A 值越小,振幅越小。

如:y=2*sin(x),其曲线如下图所示(蓝线为 y=sin(x)):

3,参数 “B" 控控制曲线的周期,B 值越大,那么周期越短,B 值越小,周期越长。

如:y=sin(2x),其曲线如下图所示(蓝线为 y=sin(x)):

4,参数 “C" 控控制曲线左右移动,C 值为正数,曲线左移,C 值为负数,曲线右移;

如:y=sin(x+1),其曲线如下图所示(蓝线为 y=sin(x)):

5,参数 “D" 控控制曲线上下移动。D 值为正数,曲线上移,D 值为负数,曲线下移;

如:y=sin(x)+1,其曲线如下图所示(蓝线为 y=sin(x)):

(三)角度与弧度

因为在使用代码去计算正弦值时,其单位一般是弧度,像C#中的”Math.Sin()“函数,而直观的效果却是角度,所以需要讲解一下角度与弧度。

1,角度

定义:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆周长的360分之中的一个时,两条射线的夹角的大小为1度。

示意图如下:

2,弧度

定义:弧度:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆的半径时,两条射线的夹角大小为1弧度。

示意图如下:

其中:AB=OA=r

3,角度与弧度的差别

最基本的差别在于角所对的弧长大小不同。度的是等于圆周长的360分之中的一个,而弧度的是等于半径。

4,角度与弧度的转换

因为:弧度角=弧长/半径

所以:

a,周角(360度)=周长/半径=2πr/r=2π

b,平角(180度)=π

由b可知:180度=π弧度

所以:

c,1度=π/180 弧度(≈0.017453弧度)
d,1弧度=180/π 度(≈57.3度)

可得转换公式:

弧度=度*π/180
度=弧度*180/π


三、动画实现

实现的思路简单而言便是利用正弦曲线的”y“和”x“值的变化。对于缓入缓出动画,就是速度的变化。

速度的定义和公式:速度在数值上等于物体运动的位移跟发生这段位移所用的时间的比值。速度的计算公式为v=Δs/Δt

控制速度,无非是”距离“与”时间“这两个量的变化。

在实现应用中,往往不会同时变化两个量,而是固定一个量,变化一个量。

在实际程序实现时,一般是固定“时间”,只变化“距离”。此处的”时间“可以理解为”时间间隔“。即在时间间隔不变的情况下,需要考虑每个时间间隔内运行的距离。

那么在正弦曲线上的体现便是等x间隔下,y的取值。

(一)简单实现

(1)实现思路:

1,通过y=sin(x)的曲线可知:y值的范围是(-1~+1)

2,将曲线上移,上移距离为1,即:y=sin(x)+1,此时y值的范围:(0~2)

3,为使y值范围变为(0~1),对函数除2,即:y=(sin(x)+1)/2

如图(蓝线为 y=sin(x)):

4,将y值乘以缓入缓出动画的摆动距离

(2)C#实现:

1,控件布局及属性

2,核心代码

 void pShowD()
{
//i是度数,不是弧度
int i = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
while (true)
{
i++;
if (i > )
{
//一个周期是360度
i = ;
}
//固定时间间隔
Thread.Sleep();
//通过公式:弧度=度*π/180,将度数i转为Math.Sin()所需要的弧度数
double dz = dMoveDistance * ( + Math.Sin(i * Math.PI / )) / ;
pSetLeft(Convert.ToInt32(dz)); }
} void pSetLeft(int i)
{
if (panel_Slider.InvokeRequired)
{
panel_Slider.Invoke(new Action<int>(pSetLeft), new object[] { i });
}
else
{
panel_Slider.Left = i;
}
}

简单实现

3,运行效果

(二)简单实现优化

通过观察上面的实现,可以发现虽然实现了缓入缓出效果,但是其”滑块“(panel_Slider)的起始位置却不是最左侧,而是从中间开始。

根据上面的公式也可以看出来,当x=0时,y=(sin(x)+1)/2=1/2,即:整个摆动距离的二分之一。

(1)优化思路

为了让滑块从最左侧开始,则需要将曲线向右移动,移动距离是π/2。

其曲线公式变为:y=(sin(x-π/2)+1)/2

如图(蓝线为 y=sin(x)):

(2)C#实现

1,布局同上。

2,核心代码

 void pShowD2()
{
//i是度数,不是弧度
int i = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
while (true)
{
i++;
if (i > )
{
//一个周期是360度
i = ;
}
//固定时间间隔
Thread.Sleep();
//通过公式:弧度=度*π/180,将度数i转为Math.Sin()所需要的弧度数
//因为i是度数,所以是(i-90)
double dz = dMoveDistance * ( + Math.Sin((i-) * Math.PI / )) / ;
pSetLeft(Convert.ToInt32(dz)); }
} void pSetLeft(int i)
{
if (panel_Slider.InvokeRequired)
{
panel_Slider.Invoke(new Action<int>(pSetLeft), new object[] { i });
}
else
{
panel_Slider.Left = i;
}
}

简单实现(优化)

3,运行效果

(三)扩展实现

在实际应用中,动画往往需要在”固定时间“内完成。

以前面实现为例,使滑块从左端滑到右端的时长固定为1秒。该怎么实现呢?

(1)实现思路

整体思路与之前的并没有什么大的区别,仍是固定”时间“,变化”距离“。

在前面的”简单实现(优化)“的基础上,需要增加下面的一些修改和补充:

1,假设”时间间隔“为:Interval,那么,在指定的1秒内,共会变化(Step=1/Interval)次。

2,那么,每次变化时度数的变化便不再是”1“,又一个周期是滑块一个来回,所以,第次变化的度数便是:Per=2π/2*Step=180/Step。

(2)C#实现

在实现时加入了匀速的对比。

1,布局及属性

2,核心代码

 void pShowD2()
{
//当前滑块的位置
double d = ;
//true/false:向右滑/向左滑
bool bToRight = true;
//时间间隔,单位:ms
int iInterval = ;
//从左到右所需要的总时间,单位:ms
int iAnimateTime = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
//需要变化的次数
double dStep = Convert.ToDouble(iAnimateTime) / iInterval;
//每次变化所增加的距离
double dPerX = dMoveDistance / dStep;
while (true)
{
d = bToRight ? d + dPerX : d - dPerX;
if (d > dMoveDistance)
{
bToRight = false;
}
if (d < )
{
bToRight = true;
} Thread.Sleep(iInterval);
int iZ = Convert.ToInt32(d);
pSetLeft2(iZ); }
}
void pSetLeft2(int i)
{
if (panel_S2.InvokeRequired)
{
panel_S2.Invoke(new Action<int>(pSetLeft2), new object[] { i });
}
else
{
panel_S2.Left = i;
}
}

1,匀速

 void pShowD()
{
//d是度数,不是弧度
double d = ;
//时间间隔,单位:ms
int iInterval = ;
//从左到右所需要的总时间,单位:ms
int iAnimateTime = ;
//移动距离要减去滑块本身的宽度
double dMoveDistance = panel_Board.Width - panel_Slider.Width;
//需要变化的次数
double dStep = Convert.ToDouble(iAnimateTime) / iInterval;
//每次变化所增加的度数
double dPer = 180.0 / dStep;
while (true)
{
d += dPer;
if (d > )
{
//一个周期是360度
d = ;
}
//固定时间间隔
Thread.Sleep(iInterval);
//通过公式:弧度=度*π/180,将度数i转为Math.Sin()所需要的弧度数
double dz = dMoveDistance * ( + Math.Sin((d - ) * Math.PI / )) / ;
pSetLeft(Convert.ToInt32(dz)); }
} void pSetLeft(int i)
{
if (panel_Slider.InvokeRequired)
{
panel_Slider.Invoke(new Action<int>(pSetLeft), new object[] { i });
}
else
{
panel_Slider.Left = i;
}
}

2,缓入缓出

3,运行效果


四、结束语

本篇主要讲的是三角函数与缓入缓出动画,但三角函数在动画中的作用不仅仅如此,比如直接使用正弦曲线的形状来绘制波浪效果——在充电、进度条等地方可以使用该效果。

而且即然知道在曲线在动画中的作用,那么便可以通过不同的函数曲线实现不同的动画效果,比如另一个非常好用的”贝塞尔曲线“,可以实现更复杂、更优雅的动画效果。

如有错误和不足之处欢迎大家批评指正。

三角函数与缓入缓出动画及C#实现(图文讲解)的更多相关文章

  1. JQuery动画之滑入滑出动画

    1. 滑入动画(类似于商店的卷帘门) $(selector).slideDown(speed, 回调函数); 解释: 此语句实现的功能为, 在XX时间内, 下拉动画, 显现元素. 当 slideDow ...

  2. 在 jQuery 中使用滑入滑出动画效果,实现二级下拉导航菜单的显示与隐藏效果

    查看本章节 查看作业目录 需求说明: 在 jQuery 中使用滑入滑出动画效果,实现二级下拉导航菜单的显示与隐藏效果 用户将光标移动到"最新动态页"或"帮助查询" ...

  3. scrollReveal(页面缓入效果插件)

    scrollReveal(页面缓入效果插件)实现页面滚动时动画加载元素效果 前面我去了解了元素距页面视图距离,想实现页面滚动是动画加载元素(https://www.cnblogs.com/chengh ...

  4. 【jquery隐藏、显示事件and提示callback】【淡入淡出fadeToggle】【滑入滑出slideToggle】【动画animate】【停止动画stop】

    1.jquery隐藏and显示事件 $("p").hide();      //隐藏事件$("p").hide(1000);  //1秒内缓慢隐藏$(" ...

  5. jQuary总结7:动画操作,显示与隐藏 淡入淡出, 滑入滑出

    1 jquery提供了三组基本动画,这些动画都是标准的.有规律的效果,jquery还提供了自定义动画的功能. 2 显示与隐藏: show([speed],[easing],[callback]) 显示 ...

  6. css transition 实现滑入滑出

    transition是css最简单的动画. 通常当一个div属性变化时,我们会立即看的变化,从旧样式到新样式是一瞬间的,嗖嗖嗖!!! 但是,如果我希望是慢慢的从一种状态,转变成另外一种状态,怎么办?  ...

  7. 包学会之浅入浅出Vue.js:结业篇(转)

    蔡述雄,现腾讯用户体验设计部QQ空间高级UI工程师.智图图片优化系统首席工程师,曾参与<众妙之门>书籍的翻译工作.目前专注前端图片优化与新技术的探研. 在第一篇<包学会之浅入浅出Vu ...

  8. 包学会之浅入浅出Vue.js:结业篇

    在第一篇<包学会之浅入浅出Vue.js:开学篇>和上一篇<包学会之浅入浅出Vue.js:升学篇>的学习中,我们首先了解了Vue环境的搭建以及两个重要思想——路由和组件的学习,通 ...

  9. mac关闭渐隐和弹出动画效果

    苹果系统应用程序的窗口和对话框每次使用的时候都有华丽的特效,但是如果你感觉这种特效显得有点慢(MacGG闲的蛋疼),那该如何取消掉他呢? 方法很简单,打开"终端"(Finder-& ...

随机推荐

  1. 【ubuntu】开机一直“/dev/sda3:clean, XXX files, XXXX blocks”解决方法

    由于该电脑是实验室公用跑模型的机子,在解决过程中,发现是 cuda 导致一直进不了系统.原因是装了两个不同版本的cuda,一个9.2,另一个10.0,因为是公用的,目前尚不清楚,怎么同时装上两个的,也 ...

  2. [PHP学习教程 - 日期/时间]001.月份第一天&最后一天(Month First Day & Last Day)

    引言:在时间处理上,对于前/后台人性化的展示当前月份最大天数,这个是网站必须要处理的一个方面.但通常这一块会由第三方类库直接包装,这里我们做一个简单的Mark. 今天,我们就为大家提供一个函数,获得指 ...

  3. [JavaWeb基础] 005.Hibernate的配置和简单使用

    1.Hibernate简介 Hibernate是一个基于Java的开源的持久化中间件,对JDBC做了轻量的封装.采用ORM映射机制,负责实现Java对象和关系数据库之间的映射,把sql语句传给数据库, ...

  4. [JavaWeb基础] 003.JAVA访问Mysql数据库

    上面两篇讲解了简单的JSP + Servlet的搭建和请求,那么后面我们肯定要用到数据交互,也就是操纵数据库的数据,包括对数字的增加,删除,修改,查询.我们就用简单的MySql来做例子 我们需要引入驱 ...

  5. jchdl - GSL实例 - LogicalLeft

    https://mp.weixin.qq.com/s/WNm4bLWzZ0oWHWa7HQ6Y6w   逻辑左移,继承自Shifter类.只需要实现shift方法即可.   参考链接 https:// ...

  6. 实现 (5).add(3).minus(2),使其输出结果为:6

    function check(n) { n = Number(n); return isNaN(n) ? 0 : n; } function add(n) { n = check(n); return ...

  7. Java实现蓝桥杯调和级数

    1/1 + 1/2 + 1/3 + 1/4 + - 在数学上称为调和级数. 它是发散的,也就是说,只要加上足够多的项,就可以得到任意大的数字. 但是,它发散的很慢: 前1项和达到 1.0 前4项和才超 ...

  8. java实现第四届蓝桥杯连续奇数和

    连续奇数和 题目描述 小明看到一本书上写着:任何数字的立方都可以表示为连续奇数的和. 比如: 2^3 = 8 = 3 + 5 3^3 = 27 = 7 + 9 + 11 4^3 = 64 = 1 + ...

  9. PAT 害死人不偿命的(3n+1)猜想

    卡拉兹(Callatz)猜想: 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把 ( 3n+1 )砍掉一半.这样一直反复砍下去,最后一定在某一步得到 n=1.卡拉兹在 195 ...

  10. ESXI多网卡网络配置

    1.两台路由器接入不同网络: 2.一台4网口服务器,网口分别为:vmnic0.vmnic1.vmnic2.vmnic3 3.ESXI6.5服务器虚拟机系统 测试环境模拟: 路由1:192.168.0. ...