学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)

我们日常生活中用的贝塞尔曲线的地方还是比较多的,我见过的例如,自定义侧边栏的动画效果,表格的下拉效果,视图的波浪循环的效果,数据分析时的折线图,自定义TabBar的时候也会用到等等,很多自定义的想要炫酷的效果都得用到。我也一直想做一些自己喜欢的效果,所以,就腾出时间,潜心研究研究。
首先我们要扫扫盲,比较清楚的去了解它:
http://blog.csdn.net/cdnight/article/details/48468653
贝塞尔曲线包括了

一阶曲线
给定点P0、P1,线性贝塞尔曲线只是一条两点之间的直线。这条线由下式给出:

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
线性公式.png
二阶曲线
二次方贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)追踪:

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
二次方公式.png
三阶曲线
P0、P1、P2、P3 四个点在平面或在三维空间中定义了三次方贝塞尔曲线。曲线起始于 P0 走向 P1 ,并从 P2 的方向来到 P3 。一般不会经过 P1 或 P2 ;这两个点只是在那里提供方向资讯。 P0 和 P1 之间的间距,决定了曲线在转而趋进 P2 之前,走向 P1 方向的“长度有多长”。
曲线的参数形式为:

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
三次方公式.png
高阶曲线
n阶贝塞尔曲线可如下判断,给定点P0、p1、...、Pn,其贝塞尔曲线即

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
n阶曲线.jpg
WTF? 公式太抽象? 那就来看看动画吧。借用上面那篇文章的动图
曲线动态图.gif
可以看到为二阶曲线,包含了P0,P1,P2三个点.
这里有个网址比较容易的让我们能够直观方便的绘制出曲线:
https://aaaaaaaty.github.io/bezierMaker.js/playground/playground.html
为了让程序有趣点,我们来画个眉毛?(直线) 学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
眉毛.png 当然咯,我们从简单的一步一步来。
首先是如何定义贝塞尔曲线
//先创建实例 UIBezierPath *bPath = [UIBezierPath bezierPath]; //然后我们可以设置它的颜色: UIColor *color = hexStrColor(@"#FF8C69"); [color set]; //然后就是它的线条宽度: bPath.lineWidth = 2.0; 基础的属性设置先用到这些。 接下来我们就要开始绘画简单的线: 线就是两个点组成的,所以我们首先设定一个起始点: //设定屏幕中间点,这个就起始点就自己根据需求设置了。 CGPoint center = (CGPoint){kSCREENWIDTH/2,kSCREENHEIGHT/2}; 将起始点移动该坐标点 [bPath moveToPoint:(CGPoint){center.x-100,center.y-50}]; //然后设定末尾的点: [bPath addLineToPoint:(CGPoint){center.x-50,center.y-50}]; //画完记得关闭绘画的路径: [bPath closePath]; //开始绘制之前组合出来的线 [bPath stroke];

然后我们再来画眼睛?(画实心圆) 学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
眼睛.png
//移动到画的中心点 [bPath moveToPoint:(CGPoint){center.x-50,center.y-40}]; //画圆 /** *以某个中心点画弧线 *@param center指定了圆弧所在正圆的圆心点坐标 *@param radius指定了圆弧所在正圆的半径 *@param startAngle 指定了起始弧度位置注意: 起始与结束这里是弧度 *@param endAngle指定了结束弧度位置 *@param clockwise指定了绘制方向,以时钟方向为判断基准看下图 */ [bPath addArcWithCenter:(CGPoint){center.x-75,center.y-40} radius:10 startAngle:0 endAngle: DEGREES_TO_RADIANS(360) clockwise:YES]; [bPath closePath]; //file 填充路径 [bPath fill];

如果设定pi的值不那么直观,我们可以用下面的宏直接填写角度
#define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180)
【学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)】angle的值可以参照该图

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
圆 .png 嗯,我们再画个嘴(弧线) 我们画个由三个点组成的曲线。

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
嘴.png 不太明白的可以用
https://aaaaaaaty.github.io/bezierMaker.js/playground/playground.html
自己画一个看看:

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
bezier.png
可以看到,我们利用三个点绘制出我们想要的弧线。
UIBezierPath *bPathB = [UIBezierPath bezierPath]; bPathB.lineWidth = 2.0; [bPathB moveToPoint:(CGPoint){center.x-60,center.y}]; [bPathB addQuadCurveToPoint:(CGPoint){center.x+60,center.y} controlPoint:(CGPoint){center.x,center.y+50}]; [bPathB stroke];

然后你通过上述方法会发现三个点竟然不是顺序的。是的。moveToPoint是p1,CurveToPoint是p3,而controlPoint是p2。
然后我们再利用其它的方式画个空心圆当做它的大肥脸。

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
脸.png
//创建CAShapeLayer对象 CAShapeLayer *shapeLayer = [CAShapeLayer layer]; shapeLayer.frame = CGRectMake(center.x-150, center.y-150, 300,300); //设置shapeLayer的尺寸和位置 shapeLayer.fillColor = [UIColor clearColor].CGColor; //填充颜色为ClearColor //设置线条的宽度和颜色 shapeLayer.lineWidth = 2.0f; shapeLayer.strokeColor = hexStrColor(@"#FF8C69").CGColor; //创建一个圆形贝塞尔曲线 UIBezierPath *aPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,300,300)]; //将贝塞尔曲线设置为CAShapeLayer的path shapeLayer.path = aPath.CGPath; //将shapeLayer添加到视图的layer上 [self.layer addSublayer:shapeLayer];

这个实现方式就比较简单了,就是你绘制了一个CAShapeLayer图层,然后利用它的路径进行绘制。
需要注意的是,shapeLayer的frame设置的x,y不是圆心,而是外圆开始的点。 那个宽高设不设无所谓。宽高设定由UUIBezierPath决定。
其他的绘制我们就简单的绘制一下了,毕竟我们的重点是动画。
矩形 学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
矩形.png
绘制矩形只需要调用bezierPathWithRectF方法,然后填入参数就可以了。 UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:(CGRect){10,kSCREENHEIGHT-154,90,60}]; [rectPath setLineWidth:2.0]; [rectPath stroke]; //实心的需要使用fill方法

圆角 学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
圆角.png 生成圆角的方法:
UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:(CGRect){110,kSCREENHEIGHT-154,90,60} byRoundingCorners:UIRectCornerTopLeft cornerRadii:(CGSize){20,20}]; [roundedRectPath setLineWidth:2.0]; [roundedRectPath fill];

cornerRadii: 表示圆角的大小咯,范围越大,圆角越圆。 奇怪的是指定了宽度就可以了,高度怎么写都不会影响。毕竟宽度可以表示半径,这高度有啥用呢byRoundingCorners: 参数的值就是指定生成哪个方位的圆角typedef NS_OPTIONS(NSUInteger, UIRectCorner) { UIRectCornerTopLeft= 1 << 0, 左上角 UIRectCornerTopRight= 1 << 1, 右上角 UIRectCornerBottomLeft= 1 << 2, 左下角 UIRectCornerBottomRight = 1 << 3, 右下角 UIRectCornerAllCorners= ~0UL 全部 };

3阶曲线 学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
三阶曲线.png 3阶曲线设置如下图:

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
三阶曲线.jpeg 我们可以通过下面的动态图看一下:

学习计划(9)|学习计划(9) - 动画 - 贝塞尔曲线(1)
文章图片
三阶曲线.gif 分为起点,终点,还有两个控制点。
可以用下面的方法进行实现:
UIBezierPath *curveRectPath = [UIBezierPath bezierPath]; [curveRectPath moveToPoint:(CGPoint){210,kSCREENHEIGHT-124}]; [curveRectPath addCurveToPoint:(CGPoint){290,kSCREENHEIGHT-124} controlPoint1:(CGPoint){250,kSCREENHEIGHT-154} controlPoint2:(CGPoint){250,kSCREENHEIGHT-94}]; [curveRectPath setLineWidth:2.0]; [curveRectPath stroke];

DEMO:
https://github.com/yanggenwei/GWAnimation/tree/master

    推荐阅读