转 贝塞尔曲线与帧动画

参考来自下面的文章,这篇文章被转了很多次,原文都不见了

http://www.cnblogs.com/moyunmo/p/3600091.html?utm_source=tuicool&utm_medium=referral

首先说贝塞尔的各种划线方法

1.利用UIbezier的初始化方法,在UIView上画bezierPath

a.利用UIbezier的初始化方法,可以创建出圆形,矩形,圆角矩形

b.使用moveToPoint设置起始点,使用addLineToPoint增加点

下面的类继承于UIView,当此CircleView添加到父视图上时,会自动调用drawRect方法

[objc]view plaincopy

//弧度转角度

#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))

//角度转弧度

#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

#import "CircleView.h"

@implementationCircleView

-(void)drawRect:(CGRect)rect

{

//1.圆形

UIBezierPath*bPath = [UIBezierPathbezierPathWithArcCenter:CGPointMake(300,300)radius:50

startAngle: DEGREES_TO_RADIANS(135)endAngle:M_PI*2clockwise:YES];

//设置颜色

[[UIColorredColor]setStroke];

//设置线宽

[bPathsetLineWidth:5];

//绘制

[bPathstroke];

//2.椭圆

UIBezierPath*ovalPath = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(200,150,100,200)];

[ovalPathsetLineWidth:5];

[ovalPathstroke];

//3.矩形

UIBezierPath*myBezierPath = [UIBezierPathbezierPathWithRect:CGRectMake(20,20,100,50)];

[[UIColorwhiteColor]setStroke];

[myBezierPathsetLineWidth:5];

[myBezierPathstroke];

//4.圆角矩形

//UIRectCorner可以设置 哪几个角是圆角,其他不变

UIBezierPath*tBPath = [UIBezierPathbezierPathWithRoundedRect:CGRectMake(220,20,100,100)

byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeftcornerRadii:CGSizeMake(20,20)];

[[UIColorgreenColor]setStroke];

[tBPathsetLineWidth:5];

[tBPathstroke];

//5.通过添加点生成任意图形

UIBezierPath* aPath = [UIBezierPathbezierPath];

aPath.lineWidth=15.0;

aPath.lineCapStyle= kCGLineCapButt;//线条终点

//round 圆形

//butt 平的 默认值 把线连接到精准的终点

//Square 平的,会把线延伸到终点再加上线宽的一半

aPath.lineJoinStyle= kCGLineJoinBevel;//拐点处理

//bevel 斜角斜面,角的外侧是平的不圆滑

//miter 斜接 角的外侧是尖的

//round 圆角

//这是起点

[aPathmoveToPoint:CGPointMake(100.0,200.0)];

//添加点

[aPathaddLineToPoint:CGPointMake(200.0,240.0)];

[aPathaddLineToPoint:CGPointMake(160,340)];

[aPathaddLineToPoint:CGPointMake(40.0,340)];

[aPathaddLineToPoint:CGPointMake(10.0,240.0)];

[aPathclosePath];//第五条线通过调用closePath方法得到的

[aPathstroke];//Draws line 根据坐标点连线

}

@end

2.二次曲线和三次曲线

盗图两张,他们解释了控制点是怎么回事

划线方法很简单

二次曲线

[objc]view plaincopy

//创建一条贝塞尔

UIBezierPath* aPath = [UIBezierPathbezierPath];

aPath.lineWidth=5.0;//宽度

aPath.lineCapStyle= kCGLineCapRound;//线条拐角

aPath.lineJoinStyle= kCGLineJoinRound;//终点处理

//起始点

[aPathmoveToPoint:CGPointMake(20,100)];

//添加两个控制点

[aPathaddQuadCurveToPoint:CGPointMake(220,100)controlPoint:CGPointMake(170,0)];

//划线

[aPathstroke];

三次曲线

[objc]view plaincopy

//三次曲线

UIBezierPath* bPath = [UIBezierPathbezierPath];

bPath.lineWidth=5.0;

bPath.lineCapStyle= kCGLineCapRound;//线条拐角

bPath.lineJoinStyle= kCGLineCapRound;//终点处理

//起始点

[bPathmoveToPoint:CGPointMake(20,250)];

//添加两个控制点

[bPathaddCurveToPoint:CGPointMake(350,250)controlPoint1:CGPointMake(310,200)controlPoint2:CGPointMake(210,400)];

[bPathstroke];

3.了解一下底层的Core Graphics

这篇文章说的够了

http://www.mamicode.com/info-detail-841887.html

[objc]view plaincopy

-(void)drawRect:(CGRect)rect

{

// Create the path data

//创建路径时间

CGMutablePathRef cgPath = CGPathCreateMutable();

//cgPath的画图接口

//给一个cgPath里面添加了多个样式,圆和椭圆会发生关联

//两个椭圆互不影响

CGPathAddEllipseInRect(cgPath,NULL, CGRectMake(100,100,50,100));

CGPathAddEllipseInRect(cgPath,NULL, CGRectMake(250,250,100,50));

//矩形

CGPathAddRect(cgPath,NULL, CGRectMake(200,500,30,100));

//    圆形

//    CGPathAddArc(cgPath, NULL, 120, 400, 100, 0, M_PI*2, YES);

//下面两句要搭配,先有起点

CGPathMoveToPoint(cgPath,NULL,200,300);

//加一段弧

CGPathAddArcToPoint(cgPath,NULL,320,250, DEGREES_TO_RADIANS(150), M_PI*2,50);

//把CGPath赋给贝塞尔曲线

UIBezierPath* aPath = [UIBezierPathbezierPath];

aPath.CGPath= cgPath;

aPath.usesEvenOddFillRule=YES;

//并不在ARC的管理范围之内。所以需要手动释放对象,释放cgPath

CGPathRelease(cgPath);

//划线

[[UIColorredColor]setStroke];

[aPathsetLineWidth:5];

[aPathstroke];

}

4.通过shapeLayer画线

这样就不用去UIView的drawRect方法里面画图了,也就是可以在ViewController里面绘制了

[objc]view plaincopy

//ShapeLayer

-(void)layerAnimation

{

//贝塞尔画圆

UIBezierPath*path = [UIBezierPathbezierPathWithArcCenter:CGPointMake(100,100)radius:100startAngle:0endAngle:M_PIclockwise:NO];

//初始化shapeLayer

self.myShapeLayer= [CAShapeLayerlayer];

_myShapeLayer.frame= _redView.bounds;

_myShapeLayer.strokeColor= [UIColorgreenColor].CGColor;//边沿线色

_myShapeLayer.fillColor= [UIColorgrayColor].CGColor;//填充色

_myShapeLayer.lineJoin= kCALineJoinMiter;//线拐点的类型

_myShapeLayer.lineCap= kCALineCapSquare;//线终点

//从贝塞尔曲线获得形状

_myShapeLayer.path= path.CGPath;

//线条宽度

_myShapeLayer.lineWidth=10;

//起始和终止

_myShapeLayer.strokeStart=0.0;

_myShapeLayer.strokeEnd=1.0;

//将layer添加进图层

[self.redView.layeraddSublayer:_myShapeLayer];

}

二、关键帧动画

[objc]view plaincopy

//关键帧动画

-(void)layerKeyFrameAnimation

{

//画一个path

UIBezierPath*path = [UIBezierPathbezierPath];

[pathmoveToPoint:CGPointMake(-40,100)];

[pathaddLineToPoint:CGPointMake(360,100)];

[pathaddLineToPoint:CGPointMake(360,200)];

[pathaddLineToPoint:CGPointMake(-40,200)];

[pathaddLineToPoint:CGPointMake(-40,300)];

[pathaddLineToPoint:CGPointMake(360,300)];

//几个固定点

NSValue*orginalValue = [NSValuevalueWithCGPoint:self.redView.layer.position];

NSValue*value_1= [NSValuevalueWithCGPoint:CGPointMake(300,300)];

NSValue*value_2= [NSValuevalueWithCGPoint:CGPointMake(400,300)];

NSValue*value_3= [NSValuevalueWithCGPoint:CGPointMake(400,400)];

//变动的属性,keyPath后面跟的属性是CALayer的属性

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

//value数组,放所有位置信息,如果设置path,此项会被忽略

keyFA.values= @[orginalValue,value_1,value_2,value_3];

//动画路径

//    keyFA.path = path.CGPath;

//该属性是一个数组,用以指定每个子路径(AB,BC,CD)的时间。如果你没有显式地对keyTimes进行设置,则系统会默认每条子路径的时间为:ti=duration/(帧数),即每条子路径的duration相等

keyFA.keyTimes= @[@(0.0),@(0.5),@(0.9),@(2)];

//动画总时间

keyFA.duration=5.0f;

//重复次数,小于0无限重复

keyFA.repeatCount=10;

/*

这个属性用以指定时间函数,类似于运动的加速度

kCAMediaTimingFunctionLinear//线性

kCAMediaTimingFunctionEaseIn//淡入

kCAMediaTimingFunctionEaseOut//淡出

kCAMediaTimingFunctionEaseInEaseOut//淡入淡出

kCAMediaTimingFunctionDefault//默认

*/

keyFA.timingFunction= [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionLinear];

/*

fillMode的作用就是决定当前对象过了非active时间段的行为. 比如动画开始之前,动画结束之后。如果是一个动画CAAnimation,则需要将其removedOnCompletion设置为NO,要不然fillMode不起作用.

下面来讲各个fillMode的意义

kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态

kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态

kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始.你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态

kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态.

//添加动画

*/

keyFA.fillMode= kCAFillModeForwards;

/*

在关键帧动画中还有一个非常重要的参数,那便是calculationMode,计算模式.该属性决定了物体在每个子路径下是跳着走还是匀速走,跟timeFunctions属性有点类似

其主要针对的是每一帧的内容为一个座标点的情况,也就是对anchorPoint 和 position 进行的动画.当在平面座标系中有多个离散的点的时候,可以是离散的,也可以直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算. calculationMode目前提供如下几种模式

kCAAnimationLinear calculationMode的默认值,表示当关键帧为座标点的时候,关键帧之间直接直线相连进行插值计算;

kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示;

kCAAnimationPaced 使得动画均匀进行,而不是按keyTimes设置的或者按关键帧平分时间,此时keyTimes和timingFunctions无效;

kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,对于曲线的形状还可以通过tensionValues,continuityValues,biasValues来进行调整自定义,这里的数学原理是Kochanek–Bartels spline,这里的主要目的是使得运行的轨迹变得圆滑;

kCAAnimationCubicPaced 看这个名字就知道和kCAAnimationCubic有一定联系,其实就是在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的.

*/

keyFA.calculationMode= kCAAnimationPaced;

//旋转的模式,auto就是沿着切线方向动,autoReverse就是转180度沿着切线动

keyFA.rotationMode= kCAAnimationRotateAuto;

//结束后是否移除动画

keyFrameAnimation.removedOnCompletion=NO;

//添加动画

[self.redView.layeraddAnimation:keyFAforKey:@""];

}

这里有个泡泡动画的demo,结合了贝塞尔曲线和帧动画,很精致

https://github.com/bnb173yjx/BubbleAnimationDemo

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

推荐阅读更多精彩内容