我们一步步来。果冻效果,类似于弹簧效果,是需要scale缩放的衰减。
我们需要一个正弦函数的指数衰减,这里用到两个表达式:Math.sin() 和 Math.exp() 。
Math.sin() 就是正弦函数,不用多解释, Math.exp(x) 是e的x次幂(e是常数2.71828)。
用Math.exp()作为倒数,就能得到一个不断衰减的正弦函数曲线:
value + Math.sin(time*20)/Math.exp(time)
Math.sin()是在-1和1之间的值,比较小,需要乘以一个数,让缩放效果更加明显:
spd = 20; maxDev = 20; value + maxDev*Math.sin(time*spd)/Math.exp(time)
这个效果还缺一个挤压,需要把x轴和y轴的缩放错开来:
spd = 20; maxDev = 20; offset = maxDev*Math.sin(time*spd)/Math.exp(time); scaleX = scale[0] + offset; scaleY = scale[1] - offset; [scaleX,scaleY]
这个表达式还可以写成:
spd = 20; maxDev = 20; scaleX = scale[0] +maxDev*Math.sin(time*spd)/Math.exp(time); scaleY = scale[1]*scale[0] / scaleX; [scaleX,scaleY]
这个函数还可以改进,引进一个变量decay,让衰减得更陡或更缓。
decay等于0.5时候:
decay等于2时候:
让动画效果的起点是图层的入点:
spd = 30; maxDev = 20; decay = 1; t = time - inPoint; offset = maxDev*Math.sin(t*spd)/Math.exp(t*decay); scaleX = scale[0] + offset; scaleY = scale[1] - offset; [scaleX,scaleY]
进一步改进,用标记点来控制:
spd = 10; //挤压拉伸的速度 maxDev = 20; //挤压拉伸的大小 decay = 1; //衰减的速度 if(marker.numKeys > 0 && marker.nearestKey(time).time < time){ t = time - marker.nearestKey(time).time; offset = maxDev*Math.sin(t*spd)/Math.exp(t*decay); scaleX = scale[0] + offset; scaleY = scale[1] - offset; transform.scale = [scaleX,scaleY]; }else{ value; }
结合其他表达式来看一下效果:
1、给位置Position打上关键帧,第一帧[960,200],第六帧[960,540],然后给其添加表达式:
e = .7; g = 3000; nMax = 500; n = 0; if (numKeys > 0){ n = nearestKey(time).index; if (key(n).time > time) n--; } if (n > 0){ t = time - key(n).time; v = -velocityAtTime(key(n).time - .001)*e; vl = length(v); if (value instanceof Array){ vu = (vl > 0) ? normalize(v) : [0,0,0]; }else{ vu = (v < 0) ? -1 : 1; } tCur = 0; segDur = 2*vl/g; tNext = segDur; nb = 1; // number of bounces while (tNext < t && nb <= nMax){ vl *= e; segDur *= e; tCur = tNext; tNext += segDur; nb++ } if(nb <= nMax){ delta = t - tCur; value + vu*delta*(vl - g*delta/2); }else{ value } }else value
2、给scale添加表达式:
spd = 10; maxDev = 20; decay = 2; if(marker.numKeys > 0 && marker.nearestKey(time).time < time){ t = time - marker.nearestKey(time).time; offset = maxDev*Math.sin(t*spd)/Math.exp(t*decay); scaleX = scale[0] + offset; scaleY = scale[1] - offset; transform.scale = [scaleX,scaleY]; }else{ value; }
3、给图层打上标记点,并将标记点移动到第六帧
4、给scale第一帧打上关键帧[100,200],给第六帧打上关键帧[100,100]
谢谢作者的文章~ 学到了,大佬的个人站做的真好!这个夜间模式很耐看,默认字体也是我喜欢的opposans哈哈哈哈