iOS中旋转加载动画的实现

http://mp.weixin.qq.com/s?__biz=MjM5OTM0MzIwMQ==&mid=210476487&idx=6&sn=6c5b81e27c496f133a674b8d672f1399&scene=0#rd

1.前言

近日一直在看KITTEN写的《A GUIDE TO IOS ANIMATION》,此乃iOS动画开发的圣经,简直手不释卷。其中有一个动画是加载动画,因为文中没有给出实现的解析,我在这里解析一下动画的实现原理,和自己加入一些新的东西。Github地址

我们可以看到,图中主要是3个球在做交换,其中中间的球基本保持位置不变,其他两个球绕着一定的轨迹做旋转位移动画,接下来我们来看代码的实现步骤。

2.三个球旋转动画

a.创建三个半径大小,颜色大小一样的圆。这里我们用到了layer的cornerRadius属性,在正方形中,我们只要设置cornerRadius的值等于height/2,就能轻易的画出一个圆形,代码如下:

UIView *ball_1 = [[UIView alloc] initWithFrame:CGRectMake(centerPoint.x - BALL_RADIUS, centerPoint.y, BALL_RADIUS, BALL_RADIUS)];

ball_1.layer.cornerRadius = BALL_RADIUS / 2;// 成为圆形

ball_1.backgroundColor = self.ballColor;

b.我们根据圆的x值不同,创建三个并排放着,大小、形状一致的圆形,接下来我们来分析一下三个圆各自的x值

c.在git图中,我们可以看到圆是绕着一定的半径,做着一个旋转的运动,在这里我们用贝塞尔曲线创作圆,在这里我们要从180度到360度,和0度到180画两端圆弧,组成一个圆形,让球1跟着这个曲线做位移运动。

CGFloat centerPointY = HEIGHT / 2 - BALL_RADIUS * 0.5;

CGFloat centerPointX = WIDTH / 2;

CGPoint centerPoint = CGPointMake(centerPointX, centerPointY);

UIView *ball_1 = [[UIView alloc] initWithFrame:CGRectMake(centerPoint.x - BALL_RADIUS, centerPoint.y, BALL_RADIUS, BALL_RADIUS)];

ball_1.layer.cornerRadius = BALL_RADIUS / 2;// 成为圆形

ball_1.backgroundColor = self.ballColor;

[self addSubview:ball_1];

self.ball_1 = ball_1;

UIView *ball_2 = [[UIView alloc] initWithFrame:CGRectMake(centerPoint.x - BALL_RADIUS * 0.5, centerPoint.y, BALL_RADIUS, BALL_RADIUS)];

ball_2.layer.cornerRadius = BALL_RADIUS / 2;// 成为圆形

ball_2.backgroundColor = self.ballColor;

[self addSubview:ball_2];

self.ball_2 = ball_2;

UIView *ball_3 = [[UIView alloc] initWithFrame:CGRectMake(centerPoint.x + BALL_RADIUS * 0.5, centerPoint.y, BALL_RADIUS, BALL_RADIUS)];

ball_3.layer.cornerRadius = BALL_RADIUS / 2;// 成为圆形

ball_3.backgroundColor = self.ballColor;

[self addSubview:ball_3];

self.ball_3 = ball_3;

// 2.1 第一个圆的曲线

UIBezierPath *path_ball_1 = [UIBezierPath bezierPath];

[path_ball_1 moveToPoint:centerBall_1];

[path_ball_1 addArcWithCenter:centerPoint radius:BALL_RADIUS startAngle:M_PI endAngle:2*M_PI clockwise:NO];

UIBezierPath *path_ball_1_1 = [UIBezierPath bezierPath];

[path_ball_1_1 addArcWithCenter:centerPoint radius:BALL_RADIUS startAngle:0 endAngle:M_PI clockwise:NO];

[path_ball_1 appendPath:path_ball_1_1];// 把两段圆弧组合起来

我们用核心动画,让球1绕着轨迹运动:

//2.2第一个圆的动画

CAKeyframeAnimation*animation_ball_1=[CAKeyframeAnimationanimationWithKeyPath:@"position"];

animation_ball_1.path=path_ball_1.CGPath;

animation_ball_1.removedOnCompletion=NO;

animation_ball_1.fillMode=kCAFillModeForwards;

animation_ball_1.calculationMode=kCAAnimationCubic;

animation_ball_1.repeatCount=1;

animation_ball_1.duration=1.4;

animation_ball_1.delegate=self;

animation_ball_1.autoreverses=NO;

animation_ball_1.timingFunction=[CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];

[self.ball_1.layeraddAnimation:animation_ball_1forKey:@"animation"];

这样我们就完成了球1的动画,我们按着这个步骤完成球3的动画。

d.球3首先是从0度到180度、180度到360度两段弧构成,在这里我们要注意一个点是在创建核心动画的时候,我们不用再成为球3的核心动画的代理,因为我们在球1中已经成为了动画的代理,这里不做代理,防止重复出现动画代理事件的触发。

//2.3第3个圆的曲线

UIBezierPath*path_ball_3=[UIBezierPathbezierPath];

[path_ball_3moveToPoint:centerBall_2];

[path_ball_3addArcWithCenter:centerPointradius:BALL_RADIUSstartAngle:0endAngle:M_PIclockwise:NO];

UIBezierPath*path_ball_3_1=[UIBezierPathbezierPath];

[path_ball_3_1addArcWithCenter:centerPointradius:BALL_RADIUSstartAngle:M_PIendAngle:M_PI*2clockwise:NO];

[path_ball_3appendPath:path_ball_3_1];

//2.4第3个圆的动画

CAKeyframeAnimation*animation_ball_3=[CAKeyframeAnimationanimationWithKeyPath:@"position"];

animation_ball_3.path=path_ball_3.CGPath;

animation_ball_3.removedOnCompletion=NO;

animation_ball_3.fillMode=kCAFillModeForwards;

animation_ball_3.calculationMode=kCAAnimationCubic;

animation_ball_3.repeatCount=1;

animation_ball_3.duration=1.4;

animation_ball_3.autoreverses=NO;

animation_ball_3.timingFunction=[CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];

[self.ball_3.layeraddAnimation:animation_ball_3forKey:@"rotation"];

3.动画的优化

在这里我们实现了球1和球3绕着一个圆做旋转位移运动,这里我们已经完成了动画的第一部分,我们来看一下效果图:

这里我门可以看到只是单纯的实现了球的旋转位移,并不像一开始的git中的动画一样。让我们一起来分析一下我们现在这个动画距离第一个动画还少了一些什么:

git中的动画在旋转的时候球1和球2分别向两边位移了一段距离

两个球在向外位移的过程中还一边缩小球的半径

球在旋转的过程中,变回原来的位置,一边变回原来的大小

在这里我们要实现这3个动画的补充,我们需要成为原来旋转动画的代理,也就是在球1的核心动画设置delegate为self,监听动画开始的事件 - (void)animationDidStart:(CAAnimation*)anim,我们需要在动画开始的时候完成3件事情,我们来看一下分析图:

a.动画开始的时候球1和球3位移一定的距离,我们来看一下位移距离的量的计算图:

self.ball_1.transform = CGAffineTransformMakeTranslation(-BALL_RADIUS, 0);

self.ball_3.transform = CGAffineTransformMakeTranslation(BALL_RADIUS, 0);

b.在位移的过程中,我们需要设置球1、球2、球3的大小,请看一下设置完位移和大小之后球1和球3的轨迹运动图像。

self.ball_1.transform = CGAffineTransformScale(self.ball_1.transform, 0.7, 0.7);

self.ball_3.transform = CGAffineTransformScale(self.ball_3.transform, 0.7, 0.7);

self.ball_2.transform = CGAffineTransformScale(self.ball_2.transform, 0.7, 0.7);

c.在一段时间后,把球1和球2的x值和size设为动画前的大小,因此我们用UIView 的animation 动画来完成这3个动画

[UIView animateWithDuration:0.3 delay:0.1 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState animations:^{

self.ball_1.transform = CGAffineTransformMakeTranslation(-BALL_RADIUS, 0);

self.ball_1.transform = CGAffineTransformScale(self.ball_1.transform, 0.7, 0.7);

self.ball_3.transform = CGAffineTransformMakeTranslation(BALL_RADIUS, 0);

self.ball_3.transform = CGAffineTransformScale(self.ball_3.transform, 0.7, 0.7);

self.ball_2.transform = CGAffineTransformScale(self.ball_2.transform, 0.7, 0.7);

} completion:^(BOOL finished) {

[UIView animateWithDuration:0.3 delay:0.1 options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState animations:^{

self.ball_1.transform = CGAffineTransformIdentity;

self.ball_3.transform = CGAffineTransformIdentity;

self.ball_2.transform = CGAffineTransformIdentity;

} completion:NULL];

}];

d.循环动画:我们在动画代理事件的- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag中调用动画开始的函数,这样在动画结束的时候就会自动的调用动画进行循环播放。

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{

[self rotationAnimation];

}

4.毛玻璃效果的添加

利用系统自带的UIVisualEffectView类来创建毛玻璃效果,并设置为self.bouns来覆盖整个视图,详细关于UIVisualEffectView的介绍请看《最近开发遇到的一些UI问题》

UIVisualEffectView *bgView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];

bgView.alpha = 0.9f;

bgView.frame = CGRectMake(0, 0, WIDTH, HEIGHT);

bgView.layer.cornerRadius = BALL_RADIUS / 2;

bgView.clipsToBounds = YES;

[self addSubview:bgView];

5.后记

最近在从OC转为Swift,自己也遇到了一些基于Swift很不错的动画,希望在学完Swift后能转为OC,并和大家分享这个过程。学习动画中遇到了很多问题,有几何学上和物理上的问题,奈何高中数学老师死得早,几何部分理解起来常常比较吃力,无奈自己爱折腾,希望能有更大的突破。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容