A GUIDE TO IOS ANIMATION 2.0笔记(一) - 玩转贝塞尔曲线

玩转贝塞尔曲线

  • 历史:由法国雷诺汽车的工程师皮诺尔·贝塞尔发明,应用于雷诺汽车设计
  • 原理铺垫:给定 n+1个数据点,生产一条曲线,使得该曲线与这些点所连接的折线相近。

第一个demo

粘性小球.gif
  • 代码

  • 思路:一个小球用四条贝塞尔曲线平分拼成,链接完成之后向内填充颜色。然后,再单独控制每条贝塞尔曲线的形状,实时调用layer[self setNeedsDisplay]以重绘- (void)drawInContext:(CGContextRef)ctx方法。其中每条弧线都有两个控制点(学过的应该有印象)。

  • 为了方便传达理念,已以下形式展示这一思路。

未命名2.gif
Screen-Shot-2015-06-13-at-15-45-13.png

小球是由弧AB、弧BC、弧CD、弧DA 四段组成,其中每段弧都绑定两个控制点:弧AB 绑定的是 C1 、 C2;弧BC 绑定的是 C3 、 C4...

问题:这些点应该以什么样的规律运动?

  • 为了方便计算各个点的坐标,引入外接矩形(图中虚线)

首先计算出这个外接矩形的位置:根据中心点的 (x,y) 分别减去矩形(宽,高)1/2 获得。

//outsideRectSize 是外接矩形边长
// 外接矩形 x
CGFloat origin_x = self.position.x - outsideRectSize/2 + (pro
gress - 0.5) * (self.frame.size.width - outsideRectSize);
// 外接矩形 y
CGFloat origin_y = self.position.y - outsideRectSize/2;
// 设置外接矩形的frame
self.outsideRect = CGRectMake(origin_x, origin_y, outsideRect
Size, outsideRectSize);
  • 个人理解:代码里的progress代表着上面视图中滑块0~1的值。计算外接矩形 X值时,...+ (pro gress - 0.5) * (self.frame.size.width - outsideRectSize)这个部分代码,代表着矩形在向左右移动的过程中,向左移B点,向右移D点,这两点在移动过程中的缓冲区。

其次还需要判断当前是向左移还是右移,左移的时候BD不动;右移的时候DB不动。(动:指的是需不需要有缓冲区)

//只要外接矩形在左侧,则改变B点;在右边,改变D点
  if (progress <= 0.5) {
       self.movePoint = POINT_B;//用枚举代表 B, D 点
       NSLog(@"B点动");
   }else{
       self.movePoint = POINT_D;
       NSLog(@"D点动");
   }

有了矩形的位置,接下来计算关键点的坐标

- (void)drawInContext:(CGContextRef)ctx{
   //A-C1、B-C2... 的距离,当设置为正方形边长的1/3.6倍时,画出来的圆弧完美贴合圆形
   CGFloat offset = self.outsideRect.size.width / 3.6;
   //A.B.C.D实际需要移动的距离.系数为滑块偏离中点0.5的绝对值再乘以2.当滑到两端的时候,movedDistance为最大值:「外接矩形宽度的1/5」.
   CGFloat movedDistance = (self.outsideRect.size.width * 1 / 6) * fabs(self.progress-0.5)*2;
   //方便下方计算各点坐标,先算出外接矩形的中心点坐标
   CGPoint rectCenter = CGPointMake(self.outsideRect.origin.x + self.outsideRect.size.width/2 , self.outsideRect.origin.y + self.outsideRect.size.height/2);
   CGPoint pointA = CGPointMake(rectCenter.x ,self.outsideRect.origin.y + movedDistance);
   CGPoint pointB = CGPointMake(self.movePoint == POINT_D ? rectCenter.x + self.outsideRect.size.width/2 : rectCenter.x + self.outsideRect.size.width/2 + movedDistance*2 ,rectCenter.y);
   CGPoint pointC = CGPointMake(rectCenter.x ,rectCenter.y + self.outsideRect.size.height/2 - movedDistance);
   CGPoint pointD = CGPointMake(self.movePoint == POINT_D ? self.outsideRect.origin.x - movedDistance*2 : self.outsideRect.origin.x, rectCenter.y);
   CGPoint c1 = CGPointMake(pointA.x + offset, pointA.y);
   CGPoint c2 = CGPointMake(pointB.x, self.movePoint == POINT_D ? pointB.y - offset : pointB.y - offset + movedDistance);
    CGPoint c3 = CGPointMake(pointB.x, self.movePoint == POINT_D ? pointB.y + offset : pointB.y + offset - movedDistance);
   CGPoint c4 = CGPointMake(pointC.x + offset, pointC.y);
   CGPoint c5 = CGPointMake(pointC.x - offset, pointC.y);
  CGPoint c6 = CGPointMake(pointD.x, self.movePoint == POINT_D ? pointD.y + offset - movedDistance : pointD.y + offset);
    CGPoint c7 = CGPointMake(pointD.x, self.movePoint == POINT_D ? pointD.y - offset + movedDistance : pointD.y - offset);
  CGPoint c8 = CGPointMake(pointA.x - offset, pointA.y);
  //外接虚线矩形
   UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:self.outsideRect];
   CGContextAddPath(ctx, rectPath.CGPath);
  CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
   CGContextSetLineWidth(ctx, 1.0);
   CGFloat dash[] = {5.0, 5.0};
   CGContextSetLineDash(ctx, 0.0, dash, 2); //1
   CGContextStrokePath(ctx); //给线条填充颜色
   //圆的边界
   UIBezierPath* ovalPath = [UIBezierPath bezierPath];
   [ovalPath moveToPoint: pointA];
   [ovalPath addCurveToPoint:pointB controlPoint1:c1 controlPoint2:c2];
   [ovalPath addCurveToPoint:pointC controlPoint1:c3 controlPoint2:c4];
   [ovalPath addCurveToPoint:pointD controlPoint1:c5 controlPoint2:c6];
   [ovalPath addCurveToPoint:pointA controlPoint1:c7 controlPoint2:c8];
   [ovalPath closePath];
    CGContextAddPath(ctx, ovalPath.CGPath);
  CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
   CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
   CGContextSetLineDash(ctx, 0, NULL, 0); //2
   CGContextDrawPath(ctx, kCGPathFillStroke); //同时给线条和线条包围的内部区域填充颜色
   //--------------  注:以下代码均为辅助观察  -------------------
  //标记出每个点并连线,方便观察,给所有关键点染色 -- 白色,辅助线颜色 -- 白色
   //语法糖:字典@{},数组@[],基本数据类型封装成对象@234,@12.0,@YES,@(234+12.0)
   CGContextSetFillColorWithColor(ctx, [UIColor yellowColor].CGColor);
   CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
   NSArray *points = @[[NSValue valueWithCGPoint:pointA],> >[NSValue valueWithCGPoint:pointB],[NSValue valueWithCGPoint:pointC],[NSValue valueWithCGPoint:pointD],[NSValue valueWithCGPoint:c1],[NSValue valueWithCGPoint:c2],[NSValue valueWithCGPoint:c3],[NSValue valueWithCGPoint:c4],[NSValue valueWithCGPoint:c5],[NSValue valueWithCGPoint:c6],[NSValue valueWithCGPoint:c7],[NSValue valueWithCGPoint:c8]];
[self drawPoint:points withContext:ctx];

//连接辅助线
UIBezierPath *helperline = [UIBezierPath bezierPath];
[helperline moveToPoint:pointA];
[helperline addLineToPoint:c1];
[helperline addLineToPoint:c2];
[helperline addLineToPoint:pointB];
[helperline addLineToPoint:c3];
[helperline addLineToPoint:c4];
[helperline addLineToPoint:pointC];
[helperline addLineToPoint:c5];
[helperline addLineToPoint:c6];
[helperline addLineToPoint:pointD];
[helperline addLineToPoint:c7];
[helperline addLineToPoint:c8];
[helperline closePath];

CGContextAddPath(ctx, helperline.CGPath);
CGFloat dash2[] = {2.0, 2.0};
CGContextSetLineDash(ctx, 0.0, dash2, 2);
CGContextStrokePath(ctx); //给辅助线条填充颜色

}

//在某个point位置画一个点,方便观察运动情况

  • (void)drawPoint:(NSArray *)points withContext:(CGContextRef)ctx{
    for (NSValue *pointValue in points) {
    CGPoint point = [pointValue CGPointValue];
    CGContextFillRect(ctx, CGRectMake(point.x - 2,point.y - 2,4,4));
    }
    }
代码中`ctx`字面意思是上下文,你可以理解为一块全局的画布。也就是说,一旦在某个地方改了画布的一些属性,其他任何使用画布的属性的时候都是改了之后的。比如上面在 `//1` 中把线条样式改成了虚线,那么在下文 `//2` 中如果不恢复成连续的直线,那么画出来的依然是`//1`中的虚线样式。

>* **个人理解:**
>
>* **结合上面后两张图片分析**:假设向左移动,发现外接矩形以相同的速度向左移动,随着移动,发现`c7,c6`两控制点在`y`轴并不会改变;`c8,c5`在`x`轴不变的情况下,`y`轴向内移动,`c1,c4`控制点与其保持平行,同时`x`轴相对不变;`c2,c3`以相同的比例向内靠近。**猜测**该向内靠近的多少与缓冲区有关连。向右移动同理。

相关阅读

注意:该笔记内容暂且待定,我觉得有必要加深一下内功,务实基础。先读读《iOS核心动画高级技巧》😁。

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

推荐阅读更多精彩内容

  • 前言:关于贝塞尔曲线与CAShapeLayer的学习 学习Demo演示: 贝塞尔曲线简单了解 使用UIBezier...
    麦穗0615阅读 17,870评论 18 149
  • AnimationCircle 用四条曲线拼接出小球的形状,逆时针开始,分别是弧AB,弧BC,弧CD,弧DA,每条...
    JoyceZhao阅读 683评论 0 5
  • 前言 前段时间看到一个挺有趣的动画效果,于是就想着实现一下,顺便练下手,这里是第一篇教程,介绍了启动动画的制作,示...
    Arthury阅读 675评论 5 11
  • #define kBlackColor [UIColor blackColor] //.h //划线 + (voi...
    CHADHEA阅读 793评论 0 1
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,110评论 5 13