iOS-进阶整理13 - 贝塞尔曲线和帧动画结合

一、贝塞尔曲线

参考来自下面的文章,这篇文章被转了很多次,原文都不见了
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方法

//弧度转角度  
#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))  
//角度转弧度  
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)  
  
#import "CircleView.h"  
  
@implementation CircleView  
  
  
-(void)drawRect:(CGRect)rect  
{  
      
    //1.圆形  
    UIBezierPath *bPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(300, 300) radius:50   
                          startAngle: DEGREES_TO_RADIANS(135) endAngle:M_PI*2 clockwise:YES];  
   
    //设置颜色  
    [[UIColor redColor]setStroke];  
    //设置线宽  
    [bPath setLineWidth:5];  
    //绘制  
    [bPath stroke];  
      
    //2.椭圆  
    UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(200, 150, 100, 200)];  
    [ovalPath setLineWidth:5];  
    [ovalPath stroke];  
      
    //3.矩形  
    UIBezierPath *myBezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, 100, 50)];  
      
    [[UIColor whiteColor]setStroke];  
    [myBezierPath setLineWidth:5];  
    [myBezierPath stroke];  
                 
    //4.圆角矩形  
    //UIRectCorner可以设置 哪几个角是圆角,其他不变  
    UIBezierPath *tBPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(220, 20, 100, 100)   
                           byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeft cornerRadii:CGSizeMake(20, 20)];  
      
    [[UIColor greenColor]setStroke];  
    [tBPath setLineWidth:5];  
    [tBPath stroke];  
                  
    //5.通过添加点生成任意图形  
      
    UIBezierPath* aPath = [UIBezierPath bezierPath];  
    aPath.lineWidth = 15.0;  
      
    aPath.lineCapStyle = kCGLineCapButt;  //线条终点  
    //round 圆形  
    //butt 平的 默认值 把线连接到精准的终点  
    //Square 平的,会把线延伸到终点再加上线宽的一半  
    aPath.lineJoinStyle = kCGLineJoinBevel;  //拐点处理  
    //bevel 斜角斜面,角的外侧是平的不圆滑  
    //miter 斜接 角的外侧是尖的  
    //round 圆角  
      
    //这是起点  
    [aPath moveToPoint:CGPointMake(100.0, 200.0)];  
      
    //添加点  
    [aPath addLineToPoint:CGPointMake(200.0, 240.0)];  
    [aPath addLineToPoint:CGPointMake(160, 340)];  
    [aPath addLineToPoint:CGPointMake(40.0, 340)];  
    [aPath addLineToPoint:CGPointMake(10.0, 240.0)];  
    [aPath closePath]; //第五条线通过调用closePath方法得到的  
      
    [aPath stroke]; //Draws line 根据坐标点连线  
      
}  
@end  

2.二次曲线和三次曲线

盗图两张,他们解释了控制点



划线方法很简单
二次曲线


//创建一条贝塞尔  
  UIBezierPath* aPath = [UIBezierPath bezierPath];  
    
  aPath.lineWidth = 5.0;//宽度  
  aPath.lineCapStyle = kCGLineCapRound;  //线条拐角  
  aPath.lineJoinStyle = kCGLineJoinRound;  //终点处理  
  //起始点  
  [aPath moveToPoint:CGPointMake(20, 100)];  
  //添加两个控制点  
  [aPath addQuadCurveToPoint:CGPointMake(220, 100) controlPoint:CGPointMake(170, 0)];  
  //划线  
  [aPath stroke];  
    

三次曲线

//三次曲线  
    
  UIBezierPath* bPath = [UIBezierPath bezierPath];  
       
  bPath.lineWidth = 5.0;  
  bPath.lineCapStyle = kCGLineCapRound;  //线条拐角  
  bPath.lineJoinStyle = kCGLineCapRound;  //终点处理  
  //起始点  
  [bPath moveToPoint:CGPointMake(20, 250)];  
    
  //添加两个控制点  
  [bPath addCurveToPoint:CGPointMake(350, 250) controlPoint1:CGPointMake(310, 200) controlPoint2:CGPointMake(210, 400)];  
    
  [bPath stroke];  
3.了解一下底层的Core Graphics

这篇文章
http://www.mamicode.com/info-detail-841887.html

-(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 = [UIBezierPath bezierPath];  
      
    aPath.CGPath = cgPath;  
      
    aPath.usesEvenOddFillRule = YES;  
      
   //并不在ARC的管理范围之内。所以需要手动释放对象,释放cgPath  
    CGPathRelease(cgPath);  
      
    //划线  
    [[UIColor redColor]setStroke];  
    [aPath setLineWidth:5];  
    [aPath stroke];  
}  
4.通过shapeLayer画线

这样就不用去UIView的drawRect方法里面画图了


//ShapeLayer  
-(void)layerAnimation  
{  
    //贝塞尔画圆  
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:100 startAngle:0 endAngle:M_PI clockwise:NO];  
      
    //初始化shapeLayer  
    self.myShapeLayer = [CAShapeLayer layer];  
    _myShapeLayer.frame = _redView.bounds;  
  
    _myShapeLayer.strokeColor = [UIColor greenColor].CGColor;//边沿线色   
    _myShapeLayer.fillColor = [UIColor grayColor].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.layer addSublayer:_myShapeLayer];          
}  

二、关键帧动画

//关键帧动画  
-(void)layerKeyFrameAnimation  
{  
    //画一个path  
    UIBezierPath *path = [UIBezierPath bezierPath];  
    [path moveToPoint:CGPointMake(-40, 100)];  
    [path addLineToPoint:CGPointMake(360, 100)];  
    [path addLineToPoint:CGPointMake(360, 200)];  
    [path addLineToPoint:CGPointMake(-40, 200)];  
    [path addLineToPoint:CGPointMake(-40, 300)];  
    [path addLineToPoint:CGPointMake(360, 300)];  
      
    //几个固定点  
    NSValue *orginalValue = [NSValue valueWithCGPoint:self.redView.layer.position];  
    NSValue *value_1 = [NSValue valueWithCGPoint:CGPointMake(300, 300)];  
    NSValue *value_2 = [NSValue valueWithCGPoint:CGPointMake(400, 300)];  
    NSValue *value_3 = [NSValue valueWithCGPoint:CGPointMake(400, 400)];  
      
    //变动的属性,keyPath后面跟的属性是CALayer的属性  
    CAKeyframeAnimation *keyFA = [CAKeyframeAnimation animationWithKeyPath:@"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 = [CAMediaTimingFunction functionWithName: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.layer addAnimation:keyFA forKey:@""];  
}  

这里有个泡泡动画的demo,结合了贝塞尔曲线和帧动画,很精致
https://github.com/bnb173yjx/BubbleAnimationDemo

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

推荐阅读更多精彩内容

  • 前言 本文只要描述了iOS中的Core Animation(核心动画:隐式动画、显示动画)、贝塞尔曲线、UIVie...
    GitHubPorter阅读 3,600评论 7 11
  • 谈谈贝塞尔曲线 最近在做项目的时候,需要用到一个动画,非常简单的动画,简单到就是直接对一个View做平移… 然而虽...
    雨润听潮阅读 5,971评论 1 16
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,462评论 6 30
  • 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你...
    Yiart阅读 3,788评论 3 34
  • 最近在做项目的时候,需要用到一个动画,非常简单的动画,简单到就是直接对一个View做平移... 然而虽然动画简单,...
    IAMDAEMON阅读 4,269评论 12 69