美文网首页
转 贝塞尔曲线与帧动画

转 贝塞尔曲线与帧动画

作者: jsagsag | 来源:发表于2017-11-29 11:57 被阅读26次

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

    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

    相关文章

      网友评论

          本文标题:转 贝塞尔曲线与帧动画

          本文链接:https://www.haomeiwen.com/subject/wnsubxtx.html