作者简介

翁志方,携程内容信息研发部“旅拍”前端开发。曾参加ACM-ICPC获银奖,目前喜欢研究各种新颖的交互和实现。

前言

动效是用户体验很重要的一部分。随着设备性能提升和人们对于用户体验越来越高的追求,动效将会越来越重要。动效要遵循客观物理规律以及人的视觉经验,符合用户预期,让用户感觉自然,才能获得用户的喜爱。

本文将从为什么探究缓动曲线、利用物理公式探究缓动曲线、常用缓动曲线、使用曲线拟合尝试剖析苹果ScrollView动效参数、使用线性插值高仿APP动效进行介绍。希望阅读后,本文能给你在制作动效时带来一点帮助。

一、为什么探究缓动曲线

动画是源自现实世界的,人类早已习惯了一个变速运动的物理环境,一个简单的匀速动画会让人相对感觉不适。所以需要让我们的动效符合物理规律。缓动曲线表述动画变化的程度与时间的关系,常用于模拟物理世界中一些常见动作。而从动画体验来说,不同的缓动曲线会带给用户不同体验。一般为:匀速运动 < 变速运动 < 物理缓动。

苹果官方的UIView提供了Linear,EaseIn,EaseOut,EaseInout还有bezier动画函数,然而只是局限于使用,知其然而不知其所以然。例如用ease-in来做小球从高处掉下的效果,这个加速效果没有遵循相关物理原理,使得出来的动画效果不太自然。

二、利用物理公式探究缓动曲线

以下以弹簧动画为例,探究一下怎样模拟出这个效果。

iOS 9提供了CASpringAnimation类实现该效果,而Web上就没有提供类似函数。但我们仍然可以通过以前学过的物理学和数学知识来做一下研究。

下面有一个弹簧块,假设它质量为1,在它不动的时候位置是x = 1,则拉伸时的距离就是x-1了:

将这比作一个动画,弹簧块在时间t时所处的位置x就可以看作动画曲线函数x = f(t)。如果我们求得这个函数公式,就可以模拟出这个动画效果了。对此,下图将通过物理学公式和数学知识进行探讨。

在 Wolfram | Alpha中输入以上公式后得出:

使用工具绘制函数得:

感觉还是蛮像一个弹簧曲线的运动轨迹的嘛。像这样,如果我们要模仿自然生活中的某个运动轨迹,可以如上探究一下背后的物理方程,运用数学知识计算,和使用合适的工具,来模拟出对应的运动曲线。但估计很多人都把这些知识还给老师了,因此如果所有曲线都要自己探究的话,就真是太难了。

不要担心,后面还有一大半的篇幅,就是帮你解决这个问题的。

三、常用缓动曲线

下面是常见的缓动曲线(tween算法),我们下面将给出对应曲线的函数公式和代码,cubic-bezier这个网站还提供了对应贝塞尔参数。

EaseIn是从慢到快的曲线,就像开车时先慢后快,EaseOut和EaseIn的曲线图像关于(0.5,0.5)中心对称,EaseInOut:分别由EaseIn、EaseOut分别缩小一半,然后再拼接一起。

Quad,Cubic,Quart ,Quint:幂函数二次到五次曲线

// Modeled after the parabola y = x^2
double fsQuadraticEaseIn(double p)
{
return p * p;
}
// Modeled after the parabola y = -x^2 + 2x
double fsQuadraticEaseOut(double p)
{
return -(p * (p - 2));
}
// Modeled after the piecewise quadratic
// y = (1/2)((2x)^2)             ; [0, 0.5)
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
double fsQuadraticEaseInOut(double p)
{
if(p < 0.5){
return 2 * p * p;
}else{
return (-2 * p * p) + (4 * p) - 1;
}
}// Modeled after the cubic y = x^3
double fsCubicEaseIn(double p)
{
return p * p * p;
}
// Modeled after the cubic y = (x - 1)^3 + 1
double fsCubicEaseOut(double p)
{
double f = (p - 1);
return f * f * f + 1;
}
// Modeled after the piecewise cubic
// y = (1/2)((2x)^3)       ; [0, 0.5)
// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
double fsCubicEaseInOut(double p)
{
if(p < 0.5){
return 4 * p * p * p;
}else{
double f = ((2 * p) - 2);
return 0.5 * f * f * f + 1;
}
}// Modeled after the quartic x^4
double fsQuarticEaseIn(double p)
{
return p * p * p * p;
}
// Modeled after the quartic y = 1 - (x - 1)^4
double fsQuarticEaseOut(double p)
{
double f = (p - 1);
return f * f * f * (1 - p) + 1;
}
// Modeled after the piecewise quartic
// y = (1/2)((2x)^4)        ; [0, 0.5)
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
double fsQuarticEaseInOut(double p)
{
if(p < 0.5){
return 8 * p * p * p * p;
}else{
double f = (p - 1);
return -8 * f * f * f * f + 1;
}
}
// Modeled after the quintic y = x^5
double fsQuinticEaseIn(double p)
{
return p * p * p * p * p;
}
// Modeled after the quintic y = (x - 1)^5 + 1
double fsQuinticEaseOut(double p)
{
double f = (p - 1);
return f * f * f * f * f + 1;
}
// Modeled after the piecewise quintic
// y = (1/2)((2x)^5)       ; [0, 0.5)
// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
double fsQuinticEaseInOut(double p)
{
if(p < 0.5){
return 16 * p * p * p * p * p;
}else{
double f = ((2 * p) - 2);
return  0.5 * f * f * f * f * f + 1;
}
}

Sine :正弦函数曲线,常用于模拟波浪和呼吸效果

// Modeled after quarter-cycle of sine wave
double fsSineEaseIn(double p)
{
return sin((p - 1) * M_PI_2) + 1;
}
// Modeled after quarter-cycle of sine wave (different phase)
double fsSineEaseOut(double p)
{
return sin(p * M_PI_2);
}
// Modeled after half sine wave
double fsSineEaseInOut(double p)
{
return 0.5 * (1 - cos(p * M_PI));
}

Expo:2^(10(x-1)),指数函数,开始很慢后期很快

// Modeled after the exponential function y = 2^(10(x - 1))
double fsExponentialEaseIn(double p)
{
return (p == 0.0) ? p : pow(2, 10 * (p - 1));
}
// Modeled after the exponential function y = -2^(-10x) + 1
double fsExponentialEaseOut(double p)
{
return (p == 1.0) ? p : 1 - pow(2, -10 * p);
}
// Modeled after the piecewise exponential
// y = (1/2)2^(10(2x - 1))         ; [0,0.5)
// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
double fsExponentialEaseInOut(double p)
{
if(p == 0.0 || p == 1.0) return p;if(p < 0.5){
return 0.5 * pow(2, (20 * p) - 10);
}else{
return -0.5 * pow(2, (-20 * p) + 10) + 1;
}
}

Circ:顾名思义就是弧(1/4圆,如果选择了InOut就是两个外切的1/4圆)

// Modeled after shifted quadrant IV of unit circle
double fsCircularEaseIn(double p)
{
return 1 - sqrt(1 - (p * p));
}
// Modeled after shifted quadrant II of unit circle         ? ?
double fsCircularEaseOut(double p)
{
return sqrt((2 - p) * p);
}
// Modeled after the piecewise circular function
// y = (1/2)(1 - sqrt(1 - 4x^2))           ; [0, 0.5)
// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
double fsCircularEaseInOut(double p)
{
if(p < 0.5){
return 0.5 * (1 - sqrt(1 - 4 * (p * p)));
}else{
return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1);
}
}

Bounce:这是个模拟小球落地的反弹曲线,运动时间每次按0.5倍衰减

double fsBounceEaseIn(double p)
{
return 1 - fsBounceEaseOut(1 - p);
}
double fsBounceEaseOut(double p)
{
if(p < 4/11.0){
return (121 * p * p)/16.0;
}
else if(p < 8/11.0){
return (363/40.0 * p * p) - (99/10.0 * p) + 17/5.0;
}
else if(p < 9/10.0){
return (4356/361.0 * p * p) - (35442/1805.0 * p) + 16061/1805.0;
}else{
return (54/5.0 * p * p) - (513/25.0 * p) + 268/25.0;
}
}
double fsBounceEaseInOut(double p)
{
if(p < 0.5){
return 0.5 * fsBounceEaseIn(p*2);
}else{
return 0.5 * fsBounceEaseOut(p * 2 - 1) + 0.5;
}
}

Back: 这是个模拟弹簧运动过阻尼曲线

// Modeled after the overshooting cubic y = x^3-x*sin(x*pi)
double fsBackEaseIn(double p)
{
return p * p * p - p * sin(p * M_PI);
}
// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
double fsBackEaseOut(double p)
{
double f = (1 - p);
return 1 - (f * f * f - f * sin(f * M_PI));
}
// Modeled after the piecewise overshooting cubic function:
// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi))           ; [0, 0.5)
// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
double fsBackEaseInOut(double p)
{
if(p < 0.5){
double f = 2 * p;
return 0.5 * (f * f * f - f * sin(f * M_PI));
}else{
double f = (1 - (2*p - 1));
return 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5;
}
}

Elastic:这是个模拟弹簧运动欠阻尼曲线,就是我们前面研究想得出的曲线,

// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
double fsElasticEaseIn(double p)
{
return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1));
}
// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
double fsElasticEaseOut(double p)
{
return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1;
}
// Modeled after the piecewise exponentially-damped sine wave:
// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1))      ; [0,0.5)
// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
double fsElasticEaseInOut(double p)
{
if(p < 0.5){
return 0.5 * sin(13 * M_PI_2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1));
}else{
return 0.5 * (sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + 2);
}
}

下面是使用MATLAB绘制的幂函数缓动曲线里程、速度、加速度随时间变化图,可以看到幂函数次数越高,曲线前期越平缓后期越陡峭,动效的动静对比也就越强。

LTMorphingLabel 用 Swift 编写的 UILabel 子类,实现了 iOS8 中 iMessage 文字变换动画。它用到了EaseInQuint,EaseOutQuint,EaseOutBack,EaseOutBounce 4个缓动曲线,下面是一些效果图,另外附上我写的OC版本源码FSMorphingLabel:

使用5阶幂函数EaseQuint突出动效的动静对比:

使用EaseOutBack模拟悬挂掉落的过程:

使用EaseOutBounce模拟自然掉落后回弹:

下面的思维导图是我对FSMorphingLabel的一些解读,建议结合源码一起查看:

四、使用Matlab曲线拟合尝试剖析苹果ScrollView动效参数

苹果公司对用户体验做的可以说是行业典范。学习经典案例不但能让我们学到新知识,还可以少走弯路。通过代码获取ScrollView开始拖动减速后滑动的速度,减速过程中每个时间段的位移,最终位移数据。我们使用matlab来分析这些数据之间的一些关系。

初始速度(V)和滑动位移(S)之间的多项式拟合:

xdata = [7.481126 7.077155 6.764386 6.615895 6.398847 6.012318 5.336042 5.037438 4.632423 2.499686 1.901368 1.376071 0.770763 0.523422 0.507804 0.460093 ];
ydata = [3732.000000 3530.000000 3374.000000 3299.500000 3191.000000 2998.000000 2660.500000 2511.000000 2309.000000 1243.500000 944.500000 682.500000 380.000000 256.500000 248.500000 225.000000 ];
p = polyfit(xdata, ydata, 1)fitxdataArr = 0:0.2:15;
yFitArr = polyval(p, fitxdataArr);plot(xdata, ydata, 'o');
hold on; grid on;
plot(fitxdataArr, yFitArr, 'linewidth',2 );
xlabel('速度(v)');
ylabel('里程(s)');
legend('原始数据', '拟合曲线')

拟合出来的结果不是猜测的匀减速二次关系,而是线性的,S = 500*V – 5; 我们可以看成是 S = 500*V;

初始速度(V)和滑动时间(T)使用2到5次的多项式拟合图:

下面是分别使用的2到5次幂函数用最小二乘法去拟合,下图红色是原始数据,蓝色是拟合后后曲线,预测明显不符合走势。

于是我们又使用了对数模型: F = x(1)*log2(xdata) + x(2);

myfun.m:

function F = myfun(x, xdata)
F = x(1)*log2(xdata) + x(2);
end

fit.m:

xdata = [7.481126 7.077155 6.764386 6.615895 6.398847 6.012318 5.336042 5.037438 4.632423 2.499686 1.901368 1.376071 0.770763 0.523422 0.507804 0.460093 ];
ydata = [3.296769 3.279325 3.246985 3.230296 3.229400 3.196763 3.160944 3.096877 3.051205 2.768784 2.634592 2.467705 2.184812 1.984712 1.950520 1.900448 ];x0 = [2 0];
[coefArr,resnorm] = lsqcurvefit(@myfun, x0,xdata, ydata)fitxdataArr = 0:0.2:20;
yFitArr = myfun(coefArr, fitxdataArr);
plot(xdata, ydata, fitxdataArr, yFitArr, 'linewidth',1 );

得到滑动时间 T = 0.3452*log2(V) + 2.3019,吻合得很好。

这边如果是匀减速的模型,初始速度和时间的比例就是线性的,这个体验不好,安卓的貌似就是匀减速,改天验证一下。

滑动时间(T)与里程(S)之间的关系:

类似上面的也使用了多项式进行拟合,发现不对,曲线在样本数据区间走势不一样,最后我们使用的指数函数F= x(1)*2.^(x(2)*xdata) + x(3)作为经验公式,初始参数X=[ 0.001 -10 0]进行模拟退火计算,得到参数 [-0.9777 -7.4895 1.0043],经过多组数据测试,发现第一个和第三个参数波动在0.01内可以近似成1,而第二个参数会随着不同初始速度大小呈反函数曲线的关系,从而无法确定。不过函数每次计算均方差都在0.001以下,可以看到下面的拟合曲线完美遮住了原始数据,可以确定指数模型是正确的。

myfun.m:

function F = myfun(x, xdata)
F = x(1)*2.^(x(2)*xdata) + x(3);
end

fit.m:

xdata = [0.000000 0.000378 0.005109 0.011560 0.018097 0.024582 0.031021 0.037514 0.043967 0.050396 0.056848 0.063343 0.069754 0.076235 0.082703 0.089150 0.095607 0.102078 0.108535 0.114984 0.121442 0.127901 0.134363 0.140835 0.147283 0.153736 0.160199 0.166660 0.173118 0.179591 0.186018 0.192399 0.198885 0.205318 0.211814 0.218280 0.224735 0.231249 0.237728 0.244167 0.250627 0.257105 0.263540 0.269978 0.276416 0.282928 0.289383 0.295862 0.302294 0.308781 0.315241 0.321681 0.328127 0.334616 0.341050 0.347515 0.353993 0.360436 0.366884 0.373369 0.379804 0.386289 0.392751 0.399191 0.405641 0.412126 0.418565 0.425037 0.431430 0.437948 0.444395 0.450879 0.457318 0.463781 0.470227 0.476694 0.483150 0.489788 0.496073 0.502528 0.509003 0.515450 0.521907 0.528384 0.534848 0.541223 0.547798 0.554215 0.560576 0.567079 0.573566 0.579977 0.586440 0.592902 0.599360 0.605827 0.612332 0.618809 0.625250 0.631715 0.638173 0.644650 0.651082 0.657577 0.663956 0.670472 0.676926 0.683405 0.689841 0.696304 0.702780 0.709226 0.715672 0.722162 0.728595 0.735059 0.741537 0.747972 0.754428 0.760873 0.767310 0.773747 0.780275 0.786729 0.793185 0.799670 0.806105 0.819003 0.825398 0.831953 0.838424 0.851283 0.857681 0.864243 0.877113 0.890031 0.896437 0.909412 0.922341 0.935256 0.948169 0.967446 0.980412 0.999779 ];
ydata = [0.000000 0.033053 0.056022 0.086835 0.117087 0.146218 0.174230 0.201681 0.228011 0.253221 0.277871 0.301961 0.324930 0.347339 0.368627 0.389916 0.410084 0.429692 0.448179 0.466667 0.484034 0.501401 0.517647 0.533894 0.549020 0.564146 0.578711 0.592717 0.606162 0.619048 0.631933 0.644258 0.656022 0.667227 0.678431 0.689076 0.699720 0.709804 0.719328 0.728852 0.737815 0.746218 0.755182 0.763025 0.770868 0.778711 0.785994 0.793277 0.800560 0.806723 0.813445 0.819608 0.825770 0.831933 0.837535 0.843137 0.848179 0.853221 0.858263 0.863305 0.867787 0.872269 0.876751 0.880672 0.885154 0.889076 0.892437 0.896359 0.899720 0.903081 0.906443 0.909804 0.913165 0.915966 0.918768 0.921569 0.924370 0.927171 0.929412 0.932213 0.934454 0.936695 0.938936 0.941176 0.943417 0.945098 0.947339 0.949020 0.950700 0.952941 0.954622 0.956303 0.957423 0.959104 0.960784 0.961905 0.963585 0.964706 0.966387 0.967507 0.968627 0.969748 0.970868 0.971989 0.973109 0.974230 0.975350 0.976471 0.977031 0.978151 0.978711 0.979832 0.980392 0.981513 0.982073 0.983193 0.983754 0.984314 0.984874 0.985434 0.986555 0.987115 0.987675 0.988235 0.988796 0.989356 0.989916 0.990476 0.991036 0.991597 0.992157 0.992717 0.993277 0.993838 0.994398 0.994958 0.995518 0.996078 0.996639 0.997199 0.997759 0.998319 0.998880 0.999440 ];x0 = [0.001  -10 0];
[coefArr,resnorm] = lsqcurvefit(@myfun, x0, xdata, ydata)fitxdataArr = 0:0.01:1;
yFitArr = myfun(coefArr, fitxdataArr);
subplot(1,2,1);
plot(xdata, ydata, fitxdataArr, yFitArr, 'linewidth',2 );
legend('原始数据', '拟合曲线');
xlabel('时间(t)');
ylabel('');
grid on,axis equalsubplot(1,2,2);
plot(xdata, ydata)
legend('原始数据');
xlabel('时间(t)');
ylabel('');
grid on,axis equal

总结我们发现苹果ScrollView减速使用的不是简单的匀减速模型,而看的是更像是复杂过阻尼模型,过阻尼模型更贴近自然,日常的关门就是过阻尼运动,能避免很吵的碰撞冲击。

五、使用线性插值高仿APP动效

上面介绍了从物理公式推导中获取运动方程的方式、使用曲线拟合的方法获取缓动公式,下面我们还有一种更加简单的方式来做出跟效果一样的动画。

AppSotre上有很多让人惊艳的APP,他们的交互值得我们学习,下面我以蘑菇街为例简单分析一下如何在没有设计稿和动效参数的情况下,使用简单的线性插值来做出几乎跟原版一模一样的交互。

首先我们打开QuickTimePlayer,点击文件下面的影片录制,然后打开对应APP页面进行视频录制。录制完成后使用GIFBrewery打开,慢动作播放对应视频,在熟悉了视频中的大部分动作后,使用XScope工具对关键动作的真实位置进行测量,结合GIFBrewery中对应的时间轴,我们就知道了一个动作的开始时间结束时间、开始位置结束位置,足够我们进行线性插值了。

一些明显使用了缓动曲线的动效,多取几个动效点,用折线段来逼近曲线,可以近似出任何动效曲线效果,近似的思想是无敌的,在实际应用中,我们无需获取到准确的函数或方程,效果一样就行。

忘记了还有一步最重要的,使用iOS image extractor提取ipa包中的所有图片,这软件就是你的专用切图师,只要有安装包,你就能拿到他们的图片。当然,随着去年iTunes的升级,现在已经无法从iTunes上面下载到ipa安装包了,建议从apk文件下手。

下面附上几个工具的icon截图:

使用xScope和GifBrwery进行关键帧参数测量:

插值核心代码,真的简单,难在上面的参数测量上:

float calculate(float begin, float end, float lowerBound, float upperBound, float curVal)
{if (curVal<lowerBound) {curVal = lowerBound;}if (curVal>upperBound) {curVal = upperBound;}float t = (curVal-lowerBound) / (upperBound-lowerBound);return begin + (end-begin)*t;;
}

下面是我仿的两个app的代码:

仿蘑菇街:

https://github.com/wengzf/MushroomGuide

仿天巡:

https://github.com/wengzf/SkyScanner

一件优秀的作品需要大量的时间去思考去打磨,仿佛破蛹成蝶。

【推荐阅读】

  • 2019携程技术峰会回顾(含PPT和视频)

  • 携程技术出书啦,点开有彩蛋~

  • 携程度假智能客服机器人背后是这么玩的

  • 微信小程序一键转百度小程序,携程火车票团队是这样做的

  • 携程的 Dubbo 之路

关注“携程技术中心”公众号

了解携程技术一手动态

干货 | 要想做好动效,你得先知道这些相关推荐

  1. 9个做好动效设计的好方法

    动态效果意味着充满生命和兴奋,为静态事物增添生命.然而,在软件方面,动态效果不仅是为了获得乐趣,也是为了解决问题. 作为人类,我们习惯于看到世界在我们周围移动.如果任何软件有连贯的动画,它都会感到活泼 ...

  2. 新晋院士:直到硕士毕业前都想做公务员,现在只对科研感兴趣

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文整合自上观新闻.新民晚报.文汇报 从一所地方院校(江西农业大学) ...

  3. 动效引擎_要做动效?这75款动效工具让你无所不能(上)

    原标题:要做动效?这75款动效工具让你无所不能(上) 动效这两年崛起非常之迅猛,几乎是网页设计领域最强大的设计趋势之一.无论是在设计师群体还是在用户当中,它的受欢迎程度都非常之高,大家都对它津津乐道. ...

  4. 趁着年轻,做点自己想做的事

    其实根据博主最近的动态也能看出来,博主准备跳槽了,然后结果是接受了OPPO给出的offer,也满足了自己想去深圳走走看看的愿望. 博主自小在农村长大,我是属于那种不用家里人管就能自我约束的人,所以成绩 ...

  5. 档案系统专用服务器属于什么设备,想做档案数字化,却不了解所需设备?3分钟让你不懂到精通!...

    原标题:想做档案数字化,却不了解所需设备?3分钟让你不懂到精通! 本期主编:橙子 近几期有好多粉丝留言表示对档案数字化很感兴趣,想了解一下档案数字化加工设备,这一期给大家出一篇干货科普,对数字化设备感 ...

  6. 有这4张表,想做不好项目进度都难

    是不是有很多项目经理都会遇到这样的问题:无论你做的项目计划有多完美,期间总会出现各种影响项目进度的事情. 于是"项目计划经常得不到很好执行,该如何有效管理项目进度?"也成了很多项目 ...

  7. 动效给程序员用什么格式_Principle: 做动效,选对软件很重要

    你有多久没做动效了?平时的工作主要是终端视觉设计,功能需求加运营需求,静态稿件加动效设计,从比例来看,动效设计其实不会占很多空间,但偶尔也会来一波.而实际场景往往是:需求是排满的,项目是紧急的,时间呢 ...

  8. 想做自媒体赚钱如何起步?

    想做自媒体不知道怎样开始?无从下手? 耐心看完本期内容,你一定会有所收获,记得点赞收藏支持一下大周. 1.2022年了还能不能做自媒体? 能! 在做自媒体的过程中肯定会有很多人劝你放弃,也有很多人说现 ...

  9. 超实用的配音软件推荐|想做短视频,还不快点进来看看

    要说当下最火的行业,当属短视频自媒体行业了.各大平台短视频区块的崛起,给我们创造了很多机会,但在加入后,却又发现没那么简单.那么,我们到底应该如何正确的加入短视频创作行列呢? 接下来我将从各个方面为您 ...

最新文章

  1. 【Scala-spark.mlib】本地矩阵乘法计算效率比较(稠密稀疏哪家强?)
  2. 周志华:“数据、算法、算力”人工智能三要素,在未来还要加上“知识”
  3. Jquery封装(学习)01
  4. 车载安卓中控改鸿蒙,教你改装车子中控安卓大屏,看一遍你就会了,改完后低配秒变高配...
  5. 发布到服务器接口404_接口测试怎么做?
  6. 【C语言进阶深度学习记录】二 有符号与无符号
  7. 卷积神经网络CNN结构
  8. windows server 2008 - 隐藏磁盘分区 (2)
  9. Serverless 如何做到快速发布?微应用平台技术实践
  10. 165体重_身高165的女性体重多少比较合适?过胖和过瘦都不太好
  11. SwitchResX Mac屏幕分辨率调整工具
  12. pytesseract识别数字
  13. python一行代码太长_一行代码让python的运行速度提高100倍,你信吗?
  14. 【超详细】Java实现学生信息管理系统
  15. iostream和stdafx.h
  16. 批量修改联系人头像_视频号pr批量剪辑0基础实操课,pr批量处理伪原创一分钟一个视频【共2节】...
  17. 爱快软路由常见问题汇编(2018-04-21)
  18. 信息安全三级易错题总结
  19. NETDMIS5.0位置度评价案例1
  20. 人工智能入门四件套,你学人工智能避不开的知识点

热门文章

  1. 84个常用的数据源网站分享!(保持更新,建议收藏)
  2. Fer2013表情识别Group_Project_Document
  3. mac mysql 自动启动_Mac设置Mysql开机启动
  4. 应用交付为什么会受到用户青睐
  5. 语义分割的常用指标详解
  6. 2023大连理工大学计算机考研信息汇总
  7. 华为Datacom认证介绍
  8. PS怎么制作下雨天玻璃水雾图片效果
  9. Python检查文件内容是否有变动
  10. 修改远程计算机时间,win10电脑中的远程协助时间限制怎么设置