本帖最后由 小篱 于 2015-12-2 15:47 编辑
在gif中一帧一帧的看一下,心里大约就有拆分的思路了。
每个人拆分的可能都不一样,答案本来就不只一种,每个阶段我会写一篇文字,这一篇我们一起看看第一阶段。
第一阶段是这样的,为了方便大家观看,我放慢了动画速度,
再回头观察动画可知,结束时,O点和D点在0(或2π)处重合,
因此,结束时可以认为弧是从2π逆时针画到0(虽然0和2π在一个点,但从0到0、从0到2π、从2π到0画弧是不一样的,推荐大家大家动手画一下)
结束时O、D我们确定了,那么开始的时候呢,我们要看下动画中O、D的运行轨迹了。
观察动画,我们可以得出O、D的运行轨迹是这样的:
可以看出,O点逆时针(逆时针可以认为角度在减小,可以再参考上文中UIBezierPath的官方文档中的那张图)绕了3/4圈到2π,D点逆时针绕了1.5圈到0;
因此我们可以得出O、D的角度变化,是这样的:
即O点从7/2的π减小到2π,D点从3π减小到0。
现在我们知道了O、D的起点,可以将前面图上的文字补全了:
由此我们可以得出,O、D在动画阶段中的角度(图中的progress取值范围0~1)
只要我们的progress从0逐渐变到1,我们O、D就逐渐从起点运动到终点了,每次变化的时候绘制从O到D逆时针的弧,我们动画就实现了。
到了这一步,我们的动画思路已经有了,重要节点的值也知道了,剩下的就是写代码了。
写代码
我们的思路可以认为是,属性变化触发重绘,
自定义CALayer的子类,重写它的这两个方法可以实现这个思路
- + (BOOL)needsDisplayForKey:(NSString *)key;
- - (void)drawInContext:(CGContextRef)ctx;
- - (void)drawInContext:(CGContextRef)ctx {
- UIBezierPath *path = [UIBezierPath bezierPath];
-
- CGFloat radius = MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)) / 2 - kLineWidth / 2;
- CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
-
- // O
- CGFloat originStart = M_PI * 7 / 2;
- CGFloat originEnd = M_PI * 2;
- CGFloat currentOrigin = originStart - (originStart - originEnd) * self.progress;
-
- // D
- CGFloat destStart = M_PI * 3;
- CGFloat destEnd = 0;
- CGFloat currentDest = destStart - (destStart - destEnd) * self.progress;
-
- [path addArcWithCenter:center radius:radius startAngle: currentOrigin endAngle:currentDest clockwise:NO];
- CGContextAddPath(ctx, path.CGPath);
- CGContextSetLineWidth(ctx, kLineWidth);
- CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor);
- CGContextStrokePath(ctx);
- }
- CGContextStrokePath(ctx);
- CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor);
- CGContextSetLineWidth(ctx, kLineWidth);
- CGContextAddPath(ctx, path.CGPath);
-
- CGFloat currentDest = destStart - (destStart - destEnd) * self.progress;
- CGFloat destEnd = 0;
- CGFloat destStart = M_PI * 3;
-
- CGFloat currentOrigin = originStart - (originStart - originEnd) * self.progress;
- CGFloat originEnd = M_PI * 2;
- CGFloat originStart = M_PI * 7 / 2;
-
- CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
-
- UIBezierPath *path = [UIBezierPath bezierPath];
至此,第一阶段代码的主要部分就完成了,
第一阶段的完整代码大家可以参考GitHub上这个项目的OneLoadingAnimationStep1目录。
上文中的@dynamic progress;的解释
由于我对property的了解还不深,对此的解释之后会补上,
目前可参考CALayer.h的这段注释
- /** Property methods. **/
-
- /* CALayer implements the standard NSKeyValueCoding protocol for all
- * Objective C properties defined by the class and its subclasses. It
- * dynamically implements missing accessor methods for properties
- * declared by subclasses.
- *
- * declared by subclasses.
- * dynamically implements missing accessor methods for properties
- * Objective C properties defined by the class and its subclasses. It
-
![锐亚教育](http://www.insideria.cn/files/default/2017/03-19/164933d4e4bd117214.jpg)
锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛
- 还没有人评论,欢迎说说您的想法!