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

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. 面向对象案例-学生信息管理系统V1.1

    1.学生类 package com.qfedu.student.entity; /** * 学生类实体 * * @author GGGXXC * */ public class Student { p ...

  2. ngnix随笔四

    1.alias path 例1. =>http://www.a.com/bbs/ root /data/vhosts/; location /bbs/{ alias /data/a.com/; ...

  3. 【Ubuntu】Ubuntu系统启动过程中,输入用户名与密码后登录一直卡在紫色界面问题(未解决,最后通过重装系统)

    0. 前言 由于本电脑为公用电脑,可能由于其他人点了图像界面中推荐的内核更新,导致原来安装的NVIDIA显卡驱动 430 与升级后的 5.0 内核不兼容,从而导致输入用户名后登录一直卡在紫色界面.在排 ...

  4. Python 每日一练(7)

    引言 今天的练习比较轻松,原本是有两题的,但是第一题那个大致看了一下,其实和之前的6个练习差不多,就是把xls中的文件数据读取出来后,进行一下处理,对于那题而言就是一个求和操作,所以就没练了,所以今天 ...

  5. windows核心编程课程实践---多线程文件搜索器(MFC界面)

    课上完了连老师见都没见一面QAQ....记录一下该小项目 效果如下: 1.实现文件搜索功能,并封装为类 1)首先是文件搜索类Rapidfinder的构造函数和析构函数和文件信息初始化函数和文件路径规格 ...

  6. C语言/Linux命令行参数argc、argv[ ]详解

    1.void main(int argc,char *argv[]) argv[]:表示的是一个指针数组,一共有argc个元素,其中存放的是指向每一个参数的指针. argc:参数个数 2.以Linux ...

  7. Web-从Java Request对象到HTTP协议

    https://mp.weixin.qq.com/s/PjcA22STEDGwRxVQweObQQ Java Web中的Request对象是哪里来的?Response对象的角色是什么? Java We ...

  8. Chisel3 - util - LFSR16

    https://mp.weixin.qq.com/s/DSdb4tmRwDTOki7mbyuu9A     实现16位线性反馈移位寄存器.可用于生成简单的伪随机数.     ​​     ​​   参 ...

  9. .NetCore3.1中的WebApi如何配置跨域

    写法 一: 1. 打开Startup.cs,定义静态变量Any,用以配置跨域. private readonly string Any = "Any"; 2. 在Configure ...

  10. css3 属性阴影效果--box-shadow,text-shadow

    1.text-shadow:h-shadow v-shadow blur color; h-shadow:水平阴影的位置,可以是负值,正值向右,负值向左 v-shadow:水平阴影的位置,可以是负值, ...