iOS - 关于贝塞尔曲线与CAShapeLayer的学习
forcamera
8年前
<p><strong>前言:</strong></p> <p>关于贝塞尔曲线与CAShapeLayer的学习</p> <p>学习Demo演示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/831e817277b31f78a6f4abbff008404a.gif"></p> <p><strong>贝塞尔曲线简单了解</strong></p> <p>使用UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中。此类是Core Graphics框架关于path的一个封装。使用此类可以定义简单的形状,如椭圆或者矩形,或者有多个直线和曲线段组成的形状。</p> <p><strong>Bezier Path 基础</strong></p> <p>UIBezierPath对象是CGPathRef数据类型的封装。path如果是基于矢量形状的,都用直线和曲线段去创建。我们使用直线段去创建矩形和多边形,使用曲线段去创建弧(arc),圆或者其他复杂的曲线形状。</p> <p>每一段都包括一个或者多个点,绘图命令定义如何去诠释这些点。每一个直线段或者曲线段的结束的地方是下一个的开始的地方。</p> <p>每一个连接的直线或者曲线段的集合成为subpath。一个UIBezierPath对象定义一个完整的路径包括一个或者多个subpaths。</p> <ul> <li> <p>创建和使用一个path对象的过程是分开的。创建path是第一步,包含一下步骤:</p> <pre> <code class="language-objectivec">(1)创建一个Bezier path对象。 (2)使用方法moveToPoint:去设置初始线段的起点。 (3)添加line或者curve去定义一个或者多个subpaths。 (4)改变UIBezierPath对象跟绘图相关的属性。</code></pre> <p>例如,我们可以设置stroked path的属性lineWidth和lineJoinStyle。也可以设置filled path的属性usesEvenOddFillRule。</p> <p>当创建path,我们应该管理path上面的点相对于原点(0,0),这样我们在随后就可以很容易的移动path了。为了绘制path对象,我们要用到stroke和fill方法。这些方法在current graphic context下渲染path的line和curve段。</p> </li> </ul> <p><strong>CAShapeLayer</strong></p> <pre> <code class="language-objectivec">- 简单介绍: CAShapeLayer继承自CALayer,因此,可使用CALayer的所有属性。但是,CAShapeLayer需要和贝塞尔曲线配合使用才有意义。 #CAShapeLayer和drawRect的比较 - 1.drawRect:属于CoreGraphics框架,占用CPU,性能消耗大 - 2.CAShapeLayer:属于CoreAnimation框架,通过GPU来渲染图形,节省性能。动画渲染直接提交给手机GPU,不消耗内存</code></pre> <p>温馨提示:drawRect只是一个方法而已,是UIView的方法,重写此方法可以完成我们的绘制图形功能。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/07c14ad856f2c5b96ee0192eae4f2782.png"></p> <p>CAShapeLayer与UIBezierPath的关系</p> <pre> <code class="language-objectivec">- 1.CAShapeLayer中shape代表形状的意思,所以需要形状才能生效 - 2.贝塞尔曲线可以创建基于矢量的路径,而UIBezierPath类是对CGPathRef的封装 - 3.贝塞尔曲线给CAShapeLayer提供路径,CAShapeLayer在提供的路径中进行渲染。路径会闭环,所以绘制出了Shape - 4.用于CAShapeLayer的贝塞尔曲线作为path,其path是一个首尾相接的闭环的曲线,即使该贝塞尔曲线不是一个闭环的曲线</code></pre> <p style="text-align:center"><img src="https://simg.open-open.com/show/8fedc38ba8f0bc50792452f1d9662139.png"></p> <p>代码示例</p> <p>CAShapeLayer与UIBezierPath画图</p> <p><strong>1.折线</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/5e0339a079dd36454149bb0b80416d78.png"></p> <pre> <code class="language-objectivec">- (IBAction)折线:(id)sender { [self clearDisplayView]; // 创建一个路径对象 UIBezierPath *linePath = [UIBezierPath bezierPath]; // 起点 [linePath moveToPoint:(CGPoint){20,20}]; // 其他点 [linePath addLineToPoint:(CGPoint){160,160}]; [linePath addLineToPoint:(CGPoint){180,50}]; // 设置路径画布 CAShapeLayer *lineLayer = [CAShapeLayer layer]; lineLayer.bounds = (CGRect){0,0,200,200}; lineLayer.position = _centerPosition; lineLayer.lineWidth = 2.0; lineLayer.strokeColor = [UIColor orangeColor].CGColor; // 边线颜色 lineLayer.path = linePath.CGPath; lineLayer.fillColor = nil; // 默认是black // 添加到图层上 [self.displayView.layer addSublayer:lineLayer]; }</code></pre> <p><strong>2. 三角形</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/8965a9dccbcfdf265133a73bad4ae0c4.png"></p> <pre> <code class="language-objectivec">- (IBAction)三角形:(id)sender { [self clearDisplayView]; // 创建一个路径对象 UIBezierPath *polyonPath = [UIBezierPath bezierPath]; // 起点-->相对于所在视图 [polyonPath moveToPoint:(CGPoint){20,40}]; // 其他点 [polyonPath addLineToPoint:(CGPoint){160,160}]; [polyonPath addLineToPoint:(CGPoint){140,50}]; [polyonPath closePath]; // 关闭路径 添加一个结尾和起点相同的点 CAShapeLayer *polygonLayer = [CAShapeLayer layer]; polygonLayer.bounds = (CGRect){0,0,160,160}; polygonLayer.position = _centerPosition; polygonLayer.lineWidth = 2; polygonLayer.strokeColor = [UIColor redColor].CGColor; // 边线的颜色 polygonLayer.path = polyonPath.CGPath; polygonLayer.fillColor = nil; [self.displayView.layer addSublayer:polygonLayer]; }</code></pre> <p><strong>3. 多边形</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/6e225d6c1433d92467569146f0d05d8b.png"></p> <pre> <code class="language-objectivec">- (IBAction)多边形:(id)sender { [self clearDisplayView]; UIBezierPath *aPath = [UIBezierPath bezierPath]; // Set the starting point of the shape. [aPath moveToPoint:CGPointMake(100, 0.0)]; // Draw the lines [aPath addLineToPoint:CGPointMake(200.0,40.0)]; [aPath addLineToPoint:(CGPoint){160,140}]; [aPath addLineToPoint:(CGPoint){40,140}]; [aPath addLineToPoint:(CGPoint){0,40}]; [aPath closePath]; CAShapeLayer *layer = [CAShapeLayer layer]; layer.bounds = (CGRect){0,0,200,160}; layer.position = _centerPosition; layer.lineWidth = 2.0; layer.lineCap = kCALineCapRound; // 线条拐角 layer.lineJoin = kCALineCapRound; // 终点处理 layer.strokeColor = [UIColor greenColor].CGColor; layer.path = aPath.CGPath; layer.fillColor = nil; // 默认为blackColor [self.displayView.layer addSublayer:layer]; }</code></pre> <p><strong>4. 椭圆和圆</strong></p> <p><img src="https://simg.open-open.com/show/89876fe3a1003c35b1c087d499b841a7.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/055772f4a10d3cc23bd97e540b55b400.png"></p> <pre> <code class="language-objectivec">- (IBAction)椭圆:(id)sender { [self clearDisplayView]; // 创建椭圆一个路径 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:(CGRect){0,0,260,200}]; CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.bounds = (CGRect){0,0,260,200}; pathLayer.position = _centerPosition; pathLayer.lineWidth = 2.0; pathLayer.strokeColor = [UIColor grayColor].CGColor; pathLayer.path = path.CGPath; pathLayer.fillColor = nil; // 默认为blackColor [self.displayView.layer addSublayer:pathLayer]; }</code></pre> <p>圆</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/3c9ed863ad9cde493ed53ccc0b521502.png"></p> <pre> <code class="language-objectivec">- (IBAction)圆:(id)sender { [self clearDisplayView]; // 创建一个路径 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:(CGRect){0,0,200,200}]; CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.bounds = (CGRect){0,0,200,200}; pathLayer.position = _centerPosition; pathLayer.lineWidth = 2.0; pathLayer.strokeColor = [UIColor orangeColor].CGColor; // 边缘颜色 pathLayer.path = path.CGPath; // pathLayer.fillColor = nil; // [self.displayView.layer addSublayer:pathLayer]; self.displayView.layer.mask = pathLayer; // layer 的 mask属性,添加蒙版 }</code></pre> <p><strong>5. 实心矩形</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/44b7bf746640c2451757d3f68146c801.png"></p> <pre> <code class="language-objectivec">- (IBAction)实心矩形:(id)sender { [self clearDisplayView]; CAShapeLayer *layer = [CAShapeLayer layer]; layer.frame = (CGRect){0,0,100,100}; layer.position = _centerPosition; layer.backgroundColor = [UIColor lightGrayColor].CGColor; [self.displayView.layer addSublayer:layer]; }</code></pre> <p><strong>6. 空心矩形</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/d3ac32b43b7e46eb6ed24e7a5a337684.png"></p> <pre> <code class="language-objectivec">- (IBAction)空心矩形:(id)sender { [self clearDisplayView]; UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(130, 10, 100, 80)]; CAShapeLayer *layer = [CAShapeLayer layer]; //填充颜色 layer.fillColor = [UIColor clearColor].CGColor; //边框颜色 layer.strokeColor = [UIColor blackColor].CGColor; layer.path = path.CGPath; [self.displayView.layer addSublayer:layer]; }</code></pre> <p><strong>7. 画圆角矩形</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/cd83c15dae7ac3ef4e6d572b227c5e74.png"></p> <pre> <code class="language-objectivec">- (IBAction)圆角矩形:(id)sender { [self clearDisplayView]; // 创建一个路径 UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:(CGRect){0,0,200,200} cornerRadius:50]; CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.bounds = (CGRect){0,0,200,200}; pathLayer.position = _centerPosition; pathLayer.lineWidth = 2.0; pathLayer.strokeColor = [UIColor redColor].CGColor; // pathLayer.fillColor = [UIColor lightGrayColor].CGColor; // 默认为blackColor // [polygonView.layer addSublayer:polygonLayer]; pathLayer.path = path.CGPath; self.displayView.layer.mask = pathLayer; // layer 的 mask属性,添加蒙版 }</code></pre> <p><strong>8. 画单角的圆角矩形的UIBezierPath相关方法</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/0966bf0e29e536cf3283d167917947a1.png"></p> <p> </p> <pre> <code class="language-objectivec">- (IBAction)单圆角矩形:(id)sender { [self clearDisplayView]; // 创建路径 UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:(CGRect){0,0,200,200} byRoundingCorners:UIRectCornerTopLeft cornerRadii:(CGSize){100,0}]; CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.bounds = (CGRect){0,0,200,200}; pathLayer.position = _centerPosition; pathLayer.lineWidth = 2.0; pathLayer.strokeColor = [UIColor grayColor].CGColor; pathLayer.path = path.CGPath; pathLayer.fillColor = nil; [self.displayView.layer addSublayer:pathLayer]; // self.displayView.layer.mask = pathLayer; }</code></pre> <p><strong>9. 画圆弧</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/3e3e4016405bf87c8736ce19410e45dc.png"></p> <pre> <code class="language-objectivec">- (IBAction)圆弧:(id)sender { [self clearDisplayView]; // 绘制路径对象 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:_centerPosition radius:50 startAngle:0 endAngle:M_PI_2 clockwise:YES]; CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.lineWidth = 2.0; pathLayer.strokeColor = [UIColor redColor].CGColor; pathLayer.fillColor = nil; pathLayer.path = path.CGPath; [self.displayView.layer addSublayer:pathLayer]; }</code></pre> <p><strong>10.折线和弧线构成的曲线**</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/b60a9f87ea1d346c4c4045f0578f827a.png"></p> <pre> <code class="language-objectivec">#pragma mark - 折线和弧线构成的曲线 - (IBAction)折线弧线曲:(id)sender { [self clearDisplayView]; // 创建路径 UIBezierPath *path = [UIBezierPath bezierPath]; // 折线 [path moveToPoint:(CGPoint){100,100}]; [path addLineToPoint:_centerPosition]; // 添加一条弧线 [path addArcWithCenter:_centerPosition radius:50 startAngle:0 endAngle:M_PI clockwise:YES]; CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.lineWidth = 2.0; pathLayer.strokeColor = [UIColor redColor].CGColor; pathLayer.fillColor = nil; pathLayer.path = path.CGPath; [self.displayView.layer addSublayer:pathLayer]; }</code></pre> <p><strong>11.二次贝塞尔曲线</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/3a393d21955dc1b7e24f321b3bfb62c4.png"></p> <pre> <code class="language-objectivec">- (IBAction)二次贝塞尔曲线:(id)sender { [self clearDisplayView]; // 绿色二次贝塞尔曲线 UIBezierPath *path1 = [UIBezierPath bezierPath]; [path1 moveToPoint:(CGPoint){0,100}]; [path1 addQuadCurveToPoint:(CGPoint){200,50} controlPoint:(CGPoint){100,200}]; CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.position = (CGPoint){100,100}; pathLayer.lineWidth = 2.0; pathLayer.strokeColor = [UIColor greenColor].CGColor; pathLayer.fillColor = nil; pathLayer.path = path1.CGPath; [self.displayView.layer addSublayer:pathLayer]; // 红色二次贝塞尔曲线 UIBezierPath *path2 = [UIBezierPath bezierPath]; [path2 moveToPoint:CGPointMake(0, 100)]; CGPoint end2Point = CGPointMake(100, 50); [path2 addQuadCurveToPoint:end2Point controlPoint:CGPointMake(100, 200)]; // 二次贝塞尔曲线 CAShapeLayer *path2Layer = [CAShapeLayer layer]; path2Layer.position = (CGPoint){100,100}; path2Layer.lineWidth = 2; path2Layer.strokeColor = [UIColor redColor].CGColor; path2Layer.fillColor = nil; // 默认为blackColor path2Layer.path = path2.CGPath; [_displayView.layer addSublayer:path2Layer]; }</code></pre> <p>起点终点相同,控制点不同</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/41fb8428ea05db256a9e1510ca05d048.png"></p> <p>总结:控制点与起点和终点所在直线偏移距离越大,曲线弧度越大。</p> <pre> <code class="language-objectivec">- (IBAction)二次贝塞尔曲线2:(id)sender { [self clearDisplayView]; CGPoint startPoint = CGPointMake(0, 100); CGPoint endPoint = CGPointMake(200, 50); // 绿色二次贝塞尔曲线 UIBezierPath *path1 = [UIBezierPath bezierPath]; [path1 moveToPoint:startPoint]; [path1 addQuadCurveToPoint:endPoint controlPoint:CGPointMake(100, 200)]; // 二次贝塞尔曲线 CAShapeLayer *path1Layer = [CAShapeLayer layer]; path1Layer.position = (CGPoint){100,100}; path1Layer.lineWidth = 2; path1Layer.strokeColor = [UIColor greenColor].CGColor; path1Layer.fillColor = nil; // 默认为blackColor path1Layer.path = path1.CGPath; [_displayView.layer addSublayer:path1Layer]; // 红色二次贝塞尔曲线 UIBezierPath *path2 = [UIBezierPath bezierPath]; [path2 moveToPoint:startPoint]; [path2 addQuadCurveToPoint:endPoint controlPoint:CGPointMake(100, 150)]; // 二次贝塞尔曲线 CAShapeLayer *path2Layer = [CAShapeLayer layer]; path2Layer.position = (CGPoint){100,100}; path2Layer.lineWidth = 2; path2Layer.strokeColor = [UIColor redColor].CGColor; path2Layer.fillColor = nil; // 默认为blackColor path2Layer.path = path2.CGPath; [_displayView.layer addSublayer:path2Layer]; }</code></pre> <p><strong>12. 三次贝塞尔曲线</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/fc086741656b38f120c6b6968b30b15f.png"></p> <pre> <code class="language-objectivec">- (IBAction)三次贝塞尔曲线:(id)sender { [self clearDisplayView]; CGPoint startPoint = CGPointMake(0, 100); CGPoint endPoint = CGPointMake(200, 100); // 绿色二次贝塞尔曲线 UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:startPoint]; [path addCurveToPoint:endPoint controlPoint1:CGPointMake(50, 75) controlPoint2:CGPointMake(150, 125)]; // 二次贝塞尔曲线 CAShapeLayer *pathLayer = [CAShapeLayer layer]; pathLayer.position = (CGPoint){100,100}; pathLayer.lineWidth = 2; pathLayer.strokeColor = [UIColor redColor].CGColor; pathLayer.fillColor = nil; // 默认为blackColor pathLayer.path = path.CGPath; [_displayView.layer addSublayer:pathLayer]; }</code></pre> <p><strong>13. 单控制点曲线</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/b1f024994740d8cca01e09f34ae12224.png"></p> <pre> <code class="language-objectivec">- (IBAction)单控制点曲线:(id)sender { [self clearDisplayView]; //贝塞尔曲线的画法是由起点、终点、控制点三个参数来画的,为了解释清楚这个点,我写了几行代码来解释它 CGPoint startPoint = CGPointMake(50, 100); CGPoint endPoint = CGPointMake(300, 100); CGPoint controlPoint = CGPointMake(175, 10); // 红点 CALayer *layer1 = [CALayer layer]; layer1.frame = CGRectMake(startPoint.x, startPoint.y, 5, 5); layer1.backgroundColor = [UIColor redColor].CGColor; CALayer *layer2 = [CALayer layer]; layer2.frame = CGRectMake(endPoint.x, endPoint.y, 5, 5); layer2.backgroundColor = [UIColor redColor].CGColor; CALayer *layer3 = [CALayer layer]; layer3.frame = CGRectMake(controlPoint.x, controlPoint.y, 5, 5); layer3.backgroundColor = [UIColor redColor].CGColor; // 画线 UIBezierPath *path = [UIBezierPath bezierPath]; CAShapeLayer *layer = [CAShapeLayer layer]; [path moveToPoint:startPoint]; [path addQuadCurveToPoint:endPoint controlPoint:controlPoint]; layer.path = path.CGPath; layer.fillColor = [UIColor clearColor].CGColor; layer.strokeColor = [UIColor blackColor].CGColor; [self.displayView.layer addSublayer:layer]; [self.displayView.layer addSublayer:layer1]; [self.displayView.layer addSublayer:layer2]; [self.displayView.layer addSublayer:layer3]; }</code></pre> <p><strong>14.双控制点曲线</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/442ba7f45e9d61e4b0196ce88b056ef9.png"></p> <pre> <code class="language-objectivec">- (IBAction)双控制点曲线:(id)sender { [self clearDisplayView]; //贝塞尔曲线的画法是由起点、终点、控制点三个参数来画的,为了解释清楚这个点,我写了几行代码来解释它 CGPoint startPoint = CGPointMake(50, 70); CGPoint endPoint = CGPointMake(300, 70); CGPoint controlPoint1 = CGPointMake(112.5, 10); CGPoint controlPoint2 = CGPointMake(237.5, 130); // 红点 CALayer *layer1 = [CALayer layer]; layer1.frame = CGRectMake(startPoint.x, startPoint.y, 5, 5); layer1.backgroundColor = [UIColor redColor].CGColor; CALayer *layer2 = [CALayer layer]; layer2.frame = CGRectMake(endPoint.x, endPoint.y, 5, 5); layer2.backgroundColor = [UIColor redColor].CGColor; CALayer *layer3 = [CALayer layer]; layer3.frame = CGRectMake(controlPoint1.x, controlPoint1.y, 5, 5); layer3.backgroundColor = [UIColor redColor].CGColor; CALayer *layer4 = [CALayer layer]; layer4.frame = CGRectMake(controlPoint2.x, controlPoint2.y, 5, 5); layer4.backgroundColor = [UIColor redColor].CGColor; // 画线 UIBezierPath *path = [UIBezierPath bezierPath]; CAShapeLayer *layer = [CAShapeLayer layer]; [path moveToPoint:startPoint]; [path addCurveToPoint:endPoint controlPoint1:controlPoint1 controlPoint2:controlPoint2]; layer.path = path.CGPath; layer.fillColor = [UIColor clearColor].CGColor; layer.strokeColor = [UIColor blackColor].CGColor; [self.displayView.layer addSublayer:layer]; [self.displayView.layer addSublayer:layer1]; [self.displayView.layer addSublayer:layer2]; [self.displayView.layer addSublayer:layer3]; [self.displayView.layer addSublayer:layer4]; }</code></pre> <p><strong>15.曲面</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/ec391fc74aeeb5f38bfe956eb287921e.png"></p> <p> </p> <p> </p> <pre> <code class="language-objectivec">- (IBAction)曲面:(id)sender { [self clearDisplayView]; CGSize size = self.displayView.frame.size; CGFloat startHeight = size.height * 0.2; CGFloat endHeight = size.height * 0.4; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0, startHeight)]; [path addLineToPoint:CGPointMake(0, endHeight)]; [path addLineToPoint:CGPointMake(size.width, endHeight)]; [path addLineToPoint:CGPointMake(size.width, startHeight)]; [path addQuadCurveToPoint:CGPointMake(0, startHeight) controlPoint:CGPointMake(size.width/2, 0)]; CAShapeLayer *layer = [CAShapeLayer layer]; layer.strokeColor = [UIColor purpleColor].CGColor; layer.fillColor = [UIColor whiteColor].CGColor; layer.path = path.CGPath; [self.displayView.layer addSublayer:layer]; }</code></pre> <p><strong>16.综合练习- 绘哆啦A梦</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/c898253aa2a0be6a7646ab42e9a393ea.png"></p> <pre> <code class="language-objectivec">#pragma mark - 绘哆啦A梦 - (IBAction)btnDuoLaAMeng_Click:(id)sender { [self clearDisplayView]; CGFloat arcCenterX = self.view.frame.size.width/2; CGFloat arcCenterY = 80; CGFloat delay = LanPangZiDuration; //头 CAShapeLayer *headLayer = [CAShapeLayer layer]; UIBezierPath *headPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(self.view.frame.size.width/2-80, 0, 160, 160) cornerRadius:80]; [self setLayer:headLayer path:headPath delay:delay*0]; //脸 CAShapeLayer *faceLayer = [CAShapeLayer layer]; UIBezierPath *facePath = [UIBezierPath bezierPath]; [facePath moveToPoint:CGPointMake(arcCenterX-80*sqrt(2.0)/2, arcCenterY+80*sqrt(2.0)/2)]; [facePath addCurveToPoint:CGPointMake(arcCenterX-30, arcCenterY-20) controlPoint1:CGPointMake(arcCenterX-80, arcCenterY+25) controlPoint2:CGPointMake(arcCenterX-80, arcCenterY-20)]; [facePath addLineToPoint:CGPointMake(arcCenterX+30, arcCenterY-20)]; [facePath addCurveToPoint:CGPointMake(arcCenterX+80*sqrt(2.0)/2, arcCenterY+80*sqrt(2.0)/2) controlPoint1:CGPointMake(arcCenterX+80, arcCenterY-20) controlPoint2:CGPointMake(arcCenterX+80, arcCenterY+25)]; [facePath addQuadCurveToPoint:CGPointMake(arcCenterX-80*sqrt(2.0)/2, arcCenterY+80*sqrt(2.0)/2) controlPoint:CGPointMake(arcCenterX, arcCenterY+105)]; [self setLayer:faceLayer path:facePath delay:delay*1]; //左眼 CAShapeLayer *leftEyeLayer = [CAShapeLayer layer]; UIBezierPath *leftEyePath = [UIBezierPath bezierPath]; [leftEyePath moveToPoint:CGPointMake(arcCenterX-30, arcCenterY-25)]; [leftEyePath addQuadCurveToPoint:CGPointMake(arcCenterX-15, arcCenterY-45) controlPoint:CGPointMake(arcCenterX-30, arcCenterY-45)]; [leftEyePath addQuadCurveToPoint:CGPointMake(arcCenterX, arcCenterY-25) controlPoint:CGPointMake(arcCenterX, arcCenterY-45)]; [leftEyePath addQuadCurveToPoint:CGPointMake(arcCenterX-15, arcCenterY-5) controlPoint:CGPointMake(arcCenterX, arcCenterY-5)]; [leftEyePath addQuadCurveToPoint:CGPointMake(arcCenterX-30, arcCenterY-25) controlPoint:CGPointMake(arcCenterX-30, arcCenterY-5)]; [self setLayer:leftEyeLayer path:leftEyePath delay:delay*2]; //左眼珠 CAShapeLayer *leftEyeBallLayer = [CAShapeLayer layer]; UIBezierPath *leftEyeBallPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX-5, arcCenterY-30) radius:2.5 startAngle:0 endAngle:2*M_PI clockwise:YES]; [self setLayer:leftEyeBallLayer path:leftEyeBallPath delay:delay*3]; //右眼 CAShapeLayer *rightEyeLayer = [CAShapeLayer layer]; UIBezierPath *rightEyePath = [UIBezierPath bezierPath]; [rightEyePath moveToPoint:CGPointMake(arcCenterX, arcCenterY-25)]; [rightEyePath addQuadCurveToPoint:CGPointMake(arcCenterX+15, arcCenterY-45) controlPoint:CGPointMake(arcCenterX, arcCenterY-45)]; [rightEyePath addQuadCurveToPoint:CGPointMake(arcCenterX+30, arcCenterY-25) controlPoint:CGPointMake(arcCenterX+30, arcCenterY-45)]; [rightEyePath addQuadCurveToPoint:CGPointMake(arcCenterX+15, arcCenterY-5) controlPoint:CGPointMake(arcCenterX+30, arcCenterY-5)]; [rightEyePath addQuadCurveToPoint:CGPointMake(arcCenterX, arcCenterY-25) controlPoint:CGPointMake(arcCenterX, arcCenterY-5)]; [self setLayer:rightEyeLayer path:rightEyePath delay:delay*4]; //右眼珠 CAShapeLayer *rightEyeBallLayer = [CAShapeLayer layer]; UIBezierPath *rightEyeBallPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX+5, arcCenterY-30) radius:2.5 startAngle:0 endAngle:2*M_PI clockwise:YES]; [self setLayer:rightEyeBallLayer path:rightEyeBallPath delay:delay*5]; //鼻子 CAShapeLayer *noseLayer = [CAShapeLayer layer]; UIBezierPath *nosePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX, arcCenterY) radius:10 startAngle:0 endAngle:2*M_PI clockwise:YES]; [self setLayer:noseLayer path:nosePath delay:delay*6]; //鼻子光晕 CAShapeLayer *noseHaloLayer = [CAShapeLayer layer]; UIBezierPath *noseHaloPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX-4, arcCenterY-5) radius:2.5 startAngle:0 endAngle:2*M_PI clockwise:YES]; [self setLayer:noseHaloLayer path:noseHaloPath delay:delay*7]; //嘴巴 CAShapeLayer *mouthLayer = [CAShapeLayer layer]; UIBezierPath *mouthPath = [UIBezierPath bezierPath]; [mouthPath moveToPoint:CGPointMake(arcCenterX-60, arcCenterY+25)]; [mouthPath addQuadCurveToPoint:CGPointMake(arcCenterX+60, arcCenterY+25) controlPoint:CGPointMake(arcCenterX, arcCenterY+90)]; [self setLayer:mouthLayer path:mouthPath delay:delay*8]; CAShapeLayer *mouthLayer1 = [CAShapeLayer layer]; UIBezierPath *mouthPath1 = [UIBezierPath bezierPath]; [mouthPath1 moveToPoint:CGPointMake(arcCenterX, arcCenterY+10)]; [mouthPath1 addLineToPoint:CGPointMake(arcCenterX, arcCenterY+55)]; [self setLayer:mouthLayer1 path:mouthPath1 delay:delay*9]; //胡子 [self addBeardFromPoint:CGPointMake(arcCenterX-58, arcCenterY-5) toPoint:CGPointMake(arcCenterX-15, arcCenterY+10) delay:delay*10]; [self addBeardFromPoint:CGPointMake(arcCenterX-68, arcCenterY+15) toPoint:CGPointMake(arcCenterX-15, arcCenterY+20) delay:delay*11]; [self addBeardFromPoint:CGPointMake(arcCenterX-61, arcCenterY+45) toPoint:CGPointMake(arcCenterX-15, arcCenterY+30) delay:delay*12]; [self addBeardFromPoint:CGPointMake(arcCenterX+58, arcCenterY-5) toPoint:CGPointMake(arcCenterX+15, arcCenterY+10) delay:delay*13]; [self addBeardFromPoint:CGPointMake(arcCenterX+68, arcCenterY+15) toPoint:CGPointMake(arcCenterX+15, arcCenterY+20) delay:delay*14]; [self addBeardFromPoint:CGPointMake(arcCenterX+61, arcCenterY+45) toPoint:CGPointMake(arcCenterX+15, arcCenterY+30) delay:delay*15]; //左手 CAShapeLayer *leftHandLayer = [CAShapeLayer layer]; UIBezierPath *leftHandPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX-95, arcCenterY+110) radius:20 startAngle:0 endAngle:2*M_PI clockwise:YES]; [self setLayer:leftHandLayer path:leftHandPath delay:delay*16]; //左胳膊 CGFloat distanceXToArcCenter = 80*cos(M_PI_2*4/9); CGFloat distanceYToArcCenter = 80*sin(M_PI_2*4/9); CAShapeLayer *leftArmLayer = [CAShapeLayer layer]; UIBezierPath *leftArmPath = [UIBezierPath bezierPath]; [leftArmPath moveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter, arcCenterY+distanceYToArcCenter)]; [leftArmPath addLineToPoint:CGPointMake(arcCenterX-95, arcCenterY+90)]; [leftArmPath addQuadCurveToPoint:CGPointMake(arcCenterX-75, arcCenterY+110) controlPoint:CGPointMake(arcCenterX-92, arcCenterY+107)]; [leftArmPath addLineToPoint:CGPointMake(arcCenterX-distanceXToArcCenter+1.5, arcCenterY+95)]; [self setLayer:leftArmLayer path:leftArmPath delay:delay*17]; //围巾 CAShapeLayer *mufflerLayer = [CAShapeLayer layer]; UIBezierPath *mufflerPath = [UIBezierPath bezierPath]; [mufflerPath moveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter, arcCenterY+distanceYToArcCenter)]; [mufflerPath addQuadCurveToPoint:CGPointMake(arcCenterX+distanceXToArcCenter, arcCenterY+distanceYToArcCenter) controlPoint:CGPointMake(arcCenterX, arcCenterY+109)]; [mufflerPath addLineToPoint:CGPointMake(arcCenterX+distanceXToArcCenter+2, arcCenterY+distanceYToArcCenter+7)]; [mufflerPath addQuadCurveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter-4, arcCenterY+distanceYToArcCenter+5) controlPoint:CGPointMake(arcCenterX, arcCenterY+115)]; [mufflerPath addLineToPoint:CGPointMake(arcCenterX-distanceXToArcCenter, arcCenterY+distanceYToArcCenter)]; [self setLayer:mufflerLayer path:mufflerPath delay:delay*18]; //身体 CAShapeLayer *bodyLayer = [CAShapeLayer layer]; UIBezierPath *bodyPath = [UIBezierPath bezierPath]; [bodyPath moveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter, arcCenterY+distanceYToArcCenter+7)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter+5, arcCenterY+150) controlPoint:CGPointMake(arcCenterX-distanceXToArcCenter+2, arcCenterY+140)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter+3, arcCenterY+170) controlPoint:CGPointMake(arcCenterX-distanceXToArcCenter, arcCenterY+160)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX-8, arcCenterY+170) controlPoint:CGPointMake(arcCenterX-(distanceXToArcCenter+5)/2, arcCenterY+175)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX+8, arcCenterY+170) controlPoint:CGPointMake(arcCenterX, arcCenterY+155)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX+distanceXToArcCenter-3, arcCenterY+170) controlPoint:CGPointMake(arcCenterX+(distanceXToArcCenter+5)/2, arcCenterY+175)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX+distanceXToArcCenter-5, arcCenterY+150) controlPoint:CGPointMake(arcCenterX+distanceXToArcCenter-2, arcCenterY+160)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX+distanceXToArcCenter, arcCenterY+distanceYToArcCenter+8) controlPoint:CGPointMake(arcCenterX+distanceXToArcCenter-2, arcCenterY+140)]; [bodyPath addQuadCurveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter, arcCenterY+distanceYToArcCenter+7) controlPoint:CGPointMake(arcCenterX, arcCenterY+115)]; [self setLayer:bodyLayer path:bodyPath delay:delay*19]; //左脚 CAShapeLayer *leftFootLayer = [CAShapeLayer layer]; UIBezierPath *leftFootPath = [UIBezierPath bezierPath]; [leftFootPath moveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter+3, arcCenterY+170)]; [leftFootPath addQuadCurveToPoint:CGPointMake(arcCenterX-distanceXToArcCenter+3, arcCenterY+195) controlPoint:CGPointMake(arcCenterX-distanceXToArcCenter-20, arcCenterY+185)]; [leftFootPath addQuadCurveToPoint:CGPointMake(arcCenterX-13, arcCenterY+195) controlPoint:CGPointMake(arcCenterX-(distanceXToArcCenter+10)/2, arcCenterY+200)]; [leftFootPath addQuadCurveToPoint:CGPointMake(arcCenterX-10, arcCenterY+170) controlPoint:CGPointMake(arcCenterX+8, arcCenterY+187)]; [self setLayer:leftFootLayer path:leftFootPath delay:delay*20]; //右脚 CAShapeLayer *rightFootLayer = [CAShapeLayer layer]; UIBezierPath *rightFootPath = [UIBezierPath bezierPath]; [rightFootPath moveToPoint:CGPointMake(arcCenterX+10, arcCenterY+170)]; [rightFootPath addQuadCurveToPoint:CGPointMake(arcCenterX+15, arcCenterY+195) controlPoint:CGPointMake(arcCenterX-12, arcCenterY+185)]; [rightFootPath addQuadCurveToPoint:CGPointMake(arcCenterX+distanceXToArcCenter-5, arcCenterY+195) controlPoint:CGPointMake(arcCenterX+(distanceXToArcCenter+20)/2, arcCenterY+200)]; [rightFootPath addQuadCurveToPoint:CGPointMake(arcCenterX+distanceXToArcCenter-3, arcCenterY+170) controlPoint:CGPointMake(arcCenterX+distanceXToArcCenter+18, arcCenterY+185)]; [self setLayer:rightFootLayer path:rightFootPath delay:delay*21]; //肚子 CAShapeLayer *bellyLayer = [CAShapeLayer layer]; UIBezierPath *bellyPath = [UIBezierPath bezierPath]; [bellyPath moveToPoint:CGPointMake(arcCenterX-30, arcCenterY+80)]; [bellyPath addCurveToPoint:CGPointMake(arcCenterX-30, arcCenterY+150) controlPoint1:CGPointMake(arcCenterX-65, arcCenterY+95) controlPoint2:CGPointMake(arcCenterX-60, arcCenterY+140)]; [bellyPath addQuadCurveToPoint:CGPointMake(arcCenterX+30, arcCenterY+150) controlPoint:CGPointMake(arcCenterX, arcCenterY+160)]; [bellyPath addCurveToPoint:CGPointMake(arcCenterX+30, arcCenterY+80) controlPoint1:CGPointMake(arcCenterX+60, arcCenterY+140) controlPoint2:CGPointMake(arcCenterX+65, arcCenterY+95)]; [bellyPath addQuadCurveToPoint:CGPointMake(arcCenterX-30, arcCenterY+80) controlPoint:CGPointMake(arcCenterX, arcCenterY+92)]; [self setLayer:bellyLayer path:bellyPath delay:delay*22]; //铃铛 CAShapeLayer *bellLayer = [CAShapeLayer layer]; UIBezierPath *bellPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX, arcCenterY+97) radius:15 startAngle:0 endAngle:2*M_PI clockwise:YES]; [self setLayer:bellLayer path:bellPath delay:delay*23]; //铃铛上的线 CAShapeLayer *bellLineLayer = [CAShapeLayer layer]; UIBezierPath *BellLinePath = [UIBezierPath bezierPath]; [BellLinePath moveToPoint:CGPointMake(arcCenterX-(sqrt(pow(15.0, 2)-pow(5.0, 2))), arcCenterY+92)]; [BellLinePath addLineToPoint:CGPointMake(arcCenterX+(sqrt(pow(15.0, 2)-pow(5.0, 2))), arcCenterY+92)]; [BellLinePath moveToPoint:CGPointMake(arcCenterX+(sqrt(pow(15.0, 2)-pow(2.0, 2))), arcCenterY+95)]; [BellLinePath addLineToPoint:CGPointMake(arcCenterX-(sqrt(pow(15.0, 2)-pow(2.0, 2))), arcCenterY+95)]; [self setLayer:bellLineLayer path:BellLinePath delay:delay*24]; //铃铛上的小圆点 CAShapeLayer *bellCirLayer = [CAShapeLayer layer]; UIBezierPath *bellCirPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX, arcCenterY+102) radius:2.5 startAngle:0 endAngle:2*M_PI clockwise:YES]; [bellCirPath moveToPoint:CGPointMake(arcCenterX, arcCenterY+104.5)]; [bellCirPath addLineToPoint:CGPointMake(arcCenterX, arcCenterY+112)]; [self setLayer:bellCirLayer path:bellCirPath delay:delay*25]; //口袋 CAShapeLayer *bagLayer = [CAShapeLayer layer]; UIBezierPath *bagPath = [UIBezierPath bezierPath]; [bagPath moveToPoint:CGPointMake(arcCenterX-40, arcCenterY+112)]; [bagPath addQuadCurveToPoint:CGPointMake(arcCenterX+40, arcCenterY+112) controlPoint:CGPointMake(arcCenterX, arcCenterY+120)]; [bagPath addCurveToPoint:CGPointMake(arcCenterX-40, arcCenterY+112) controlPoint1:CGPointMake(arcCenterX+28, arcCenterY+160) controlPoint2:CGPointMake(arcCenterX-28, arcCenterY+160)]; [self setLayer:bagLayer path:bagPath delay:delay*26]; //右手 CAShapeLayer *rightHandLayer = [CAShapeLayer layer]; UIBezierPath *rightHandPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(arcCenterX+85*cos(27/180.0*M_PI), arcCenterY-85*sin(27/180.0*M_PI)) radius:20 startAngle:0 endAngle:2*M_PI clockwise:YES]; [self setLayer:rightHandLayer path:rightHandPath delay:delay*27]; //右胳膊 CAShapeLayer *rightArmLayer = [CAShapeLayer layer]; UIBezierPath *rightArmPath = [UIBezierPath bezierPath]; [rightArmPath moveToPoint:CGPointMake(arcCenterX+80*cos(13/180.0*M_PI), arcCenterY-80*sin(13/180.0*M_PI))]; [rightArmPath addQuadCurveToPoint:CGPointMake(arcCenterX+distanceXToArcCenter, arcCenterY+distanceYToArcCenter) controlPoint:CGPointMake(arcCenterX+80*cos(13/180.0*M_PI)+9, arcCenterY+20)]; [rightArmPath addLineToPoint:CGPointMake(arcCenterX+distanceXToArcCenter, arcCenterY+distanceYToArcCenter+25)]; [rightArmPath addQuadCurveToPoint:CGPointMake(arcCenterX+93*cos(15/180.0*M_PI), arcCenterY-93*sin(15/180.0*M_PI)) controlPoint:CGPointMake(arcCenterX+90*cos(13/180.0*M_PI)+15, arcCenterY+25)]; [rightArmPath addQuadCurveToPoint:CGPointMake(arcCenterX+80*cos(13/180.0*M_PI), arcCenterY-80*sin(13/180.0*M_PI)) controlPoint:CGPointMake(arcCenterX+80*cos(13/180.0*M_PI)+5, arcCenterY-93*sin(15/180.0*M_PI)+5)]; [self setLayer:rightArmLayer path:rightArmPath delay:delay*28]; //上色 [self setLayerColor:faceLayer color:[UIColor whiteColor] delay:delay*16]; [self setLayerColor:leftEyeLayer color:[UIColor whiteColor] delay:delay*29]; [self setLayerColor:rightEyeLayer color:[UIColor whiteColor] delay:delay*29]; [self setLayerColor:leftEyeBallLayer color:[UIColor blackColor] delay:delay*29]; [self setLayerColor:rightEyeBallLayer color:[UIColor blackColor] delay:delay*29]; [self setLayerColor:noseLayer color:[UIColor redColor] delay:delay*29]; [self setLayerColor:noseHaloLayer color:[UIColor whiteColor] delay:delay*29]; [self setLayerColor:headLayer color:[UIColor colorWithRed:21/255.0 green:159/255.0 blue:237/255.0 alpha:1] delay:delay*29]; [self setLayerColor:leftArmLayer color:[UIColor colorWithRed:21/255.0 green:159/255.0 blue:237/255.0 alpha:1] delay:delay*29]; [self setLayerColor:leftHandLayer color:[UIColor whiteColor] delay:delay*29]; [self setLayerColor:mufflerLayer color:[UIColor redColor] delay:delay*29]; [self setLayerColor:bellyLayer color:[UIColor whiteColor] delay:delay*29]; [self setLayerColor:bellLayer color:[UIColor yellowColor] delay:delay*29]; [self setLayerColor:bodyLayer color:[UIColor colorWithRed:21/255.0 green:159/255.0 blue:237/255.0 alpha:1] delay:delay*29]; [self setLayerColor:rightHandLayer color:[UIColor whiteColor] delay:delay*29]; [self setLayerColor:rightArmLayer color:[UIColor colorWithRed:21/255.0 green:159/255.0 blue:237/255.0 alpha:1] delay:delay*29]; [self performSelector:@selector(showHello) withObject:nil afterDelay:delay*29]; } - (void)addBeardFromPoint:(CGPoint)fromPoint toPoint:(CGPoint)toPoint delay:(CFTimeInterval)delay { CAShapeLayer *beardLayer1 = [CAShapeLayer layer]; UIBezierPath *beardPath1 = [UIBezierPath bezierPath]; [beardPath1 moveToPoint:fromPoint]; [beardPath1 addLineToPoint:toPoint]; [self setLayer:beardLayer1 path:beardPath1 delay:delay]; } - (void)setLayerColor:(CAShapeLayer *)layer color:(UIColor *)color delay:(CFTimeInterval)delay { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ layer.fillColor = color.CGColor; }); } - (void)setLayer:(CAShapeLayer *)layer path:(UIBezierPath *)path delay:(CFTimeInterval)delay { layer.path = path.CGPath; layer.fillColor = [UIColor clearColor].CGColor; layer.strokeColor = [UIColor lightGrayColor].CGColor; __weak typeof(self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakSelf.displayView.layer addSublayer:layer]; [weakSelf addAnimation:layer duration:LanPangZiDuration]; }); } - (void)showHello { UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2+90, 0, 70, 30)]; label.textAlignment = NSTextAlignmentCenter; label.textColor = [UIColor colorWithRed:21/255.0 green:159/255.0 blue:237/255.0 alpha:1]; label.text = @"Hello"; label.font = [UIFont fontWithName:@"Chalkduster" size:20]; [self.displayView addSubview:label]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; animation.fromValue = @(0); animation.toValue = @(1); animation.duration = 0.5f; [label.layer addAnimation:animation forKey:nil]; }</code></pre> <p><strong>参考:</strong></p> <pre> <code class="language-objectivec">1. [iOS CAShapeLayer & UIBezierPath画线、画图](http://www.cnblogs.com/jaesun/p/iOS-CAShapeLayerUIBezierPath-hua-xian.html) 2. [iOS开发 贝塞尔曲线UIBezierPath](http://www.cnblogs.com/ioshe/p/5481827.html) 3. [iOS_贝塞尔曲线初级篇](http://blog.csdn.net/qq_16437739/article/details/53284064) 4. [iOS CAShapeLayer精讲](http://www.jianshu.com/p/5f08035056f6)</code></pre> <p> </p> <p> </p> <p>来自:http://www.jianshu.com/p/b1c38a3a67a9</p> <p> </p>