CAShapeLayer 与贝塞尔曲线

一 CAShapeLayer 简介

1,CAShapeLayer继承至CALayer,可以使用CALayer的所有属性

2,CAShapeLayer需要与贝塞尔曲线配合使用才有意义;单独使用毫无意义

3,使用CAShapeLayer与贝塞尔可以实现不在view的drawRect方法中画出一些想要的图形;

4,CAShapeLayer属于Core  Animation框架,其动画渲染直接提交到手机的GPU当中,相较于view的drawRect方法使用CPU渲染而言,其效率极高,

能大大优化内存使用情况。

drawRect 属于Core Graphics 框架,走CPU,耗性能较大。

5,示例:

@interface SubLayerVC ()

@property (nonatomic, strong) NSTimer      *timer;
@property (nonatomic, strong) CAShapeLayer *shapeLayer;

@end

@implementation SubLayerVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    // 创建shapeLayer
    _shapeLayer = [CAShapeLayer layer];
    _shapeLayer.frame         = (CGRect){CGPointMake(0, 0), CGSizeMake(200, 200)};
    _shapeLayer.position      = self.view.center;
    _shapeLayer.path          = [self getStar1BezierPath].CGPath;
    _shapeLayer.fillColor     = [UIColor clearColor].CGColor;
    _shapeLayer.strokeColor   = [UIColor redColor].CGColor;
    _shapeLayer.lineWidth     = 2.f;
    [self.view.layer addSublayer:_shapeLayer];
    
    // 创建定时器
    _timer = [NSTimer scheduledTimerWithTimeInterval:1.f
                                              target:self
                                            selector:@selector(pathAnimation)
                                            userInfo:nil
                                             repeats:YES];
    
    
}

/**
 *  执行path的动画
 */
- (void)pathAnimation {
    static int i = 0;
    if (i++ % 2 == 0) {
        CABasicAnimation *circleAnim = [CABasicAnimation animationWithKeyPath:@"path"];
        circleAnim.removedOnCompletion = NO;
        circleAnim.duration            = 1;
        circleAnim.fromValue           = (__bridge id)[self getStar1BezierPath].CGPath;
        circleAnim.toValue             = (__bridge id)[self getStar2BezierPath].CGPath;
        _shapeLayer.path               = [self getStar2BezierPath].CGPath;
        [_shapeLayer addAnimation:circleAnim forKey:@"animateCirclePath"];
    } else {
        CABasicAnimation *circleAnim = [CABasicAnimation animationWithKeyPath:@"path"];
        circleAnim.removedOnCompletion = NO;
        circleAnim.duration            = 1;
        circleAnim.fromValue           = (__bridge id)[self getStar2BezierPath].CGPath;
        circleAnim.toValue             = (__bridge id)[self getStar1BezierPath].CGPath;
        _shapeLayer.path               = [self getStar1BezierPath].CGPath;
        [_shapeLayer addAnimation:circleAnim forKey:@"animateCirclePath"];
    }
}

/**
 *  贝塞尔曲线1
 *
 *  @return 贝塞尔曲线
 */
-(UIBezierPath *)getStar1BezierPath {
    //// Star Drawing
    UIBezierPath* starPath = [UIBezierPath bezierPath];
    [starPath moveToPoint: CGPointMake(22.5, 2.5)];
    [starPath addLineToPoint: CGPointMake(28.32, 14.49)];
    [starPath addLineToPoint: CGPointMake(41.52, 16.32)];
    [starPath addLineToPoint: CGPointMake(31.92, 25.56)];
    [starPath addLineToPoint: CGPointMake(34.26, 38.68)];
    [starPath addLineToPoint: CGPointMake(22.5, 32.4)];
    [starPath addLineToPoint: CGPointMake(10.74, 38.68)];
    [starPath addLineToPoint: CGPointMake(13.08, 25.56)];
    [starPath addLineToPoint: CGPointMake(3.48, 16.32)];
    [starPath addLineToPoint: CGPointMake(16.68, 14.49)];
    [starPath closePath];
    
    return starPath;
}
/**
 *  贝塞尔曲线2
 *
 *  @return 贝塞尔曲线
 */
-(UIBezierPath *)getStar2BezierPath {
    //// Star Drawing
    UIBezierPath* starPath = [UIBezierPath bezierPath];
    [starPath moveToPoint: CGPointMake(22.5, 2.5)];
    [starPath addLineToPoint: CGPointMake(32.15, 9.21)];
    [starPath addLineToPoint: CGPointMake(41.52, 16.32)];
    [starPath addLineToPoint: CGPointMake(38.12, 27.57)];
    [starPath addLineToPoint: CGPointMake(34.26, 38.68)];
    [starPath addLineToPoint: CGPointMake(22.5, 38.92)];
    [starPath addLineToPoint: CGPointMake(10.74, 38.68)];
    [starPath addLineToPoint: CGPointMake(6.88, 27.57)];
    [starPath addLineToPoint: CGPointMake(3.48, 16.32)];
    [starPath addLineToPoint: CGPointMake(12.85, 9.21)];
    [starPath closePath];
    
    return starPath;
}

二贝赛尔曲线与CAShapeLayer的关系

1,CAShapeLayer,含shape,顾名思义,它需要一个形状才能生效;

2,贝塞尔曲线可以创建基于矢量的路径

3,贝塞尔曲线给CAShapeLayer提供路径,CAShapeLayer在提供的路径中进行渲染,路径会闭环,所以路径绘制出了shape。

4,用于CAShapeLayer的贝塞尔曲线作为path,其path是一个首尾相接的闭环的曲线,即使该贝塞尔曲线不是一个闭环的曲线。

shape.masksToBounds = YES ; //禁止内容显示超出CAShapeLayer的frame值。

贝塞尔曲线的frame值与CAShapeLayer的frame值互不干扰,CAShaperLayer的frame值不能小于贝塞尔曲线的frame值。

 

三 CAShapeLayer 之 strokeStart与strokeEnd动画

1,将shapeLayer的fillColor设置为透明背景

2,设置线条的宽度(lineWidth)的值

3,设置线条的颜色

4,将strokeStart值设定为0,然后让stokeEnd的值变化触发隐式动画

   - (void)viewDidLoad {
       [super viewDidLoad];
        
    self.view.backgroundColor = [UIColor whiteColor];
    // 创建椭圆形贝塞尔曲线
    UIBezierPath *oval        = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 100)];
    
    // 创建CAShapeLayer
    _shapeLayer3               = [CAShapeLayer layer];
    _shapeLayer3.frame         = CGRectMake(0, 0, 100, 100);
    _shapeLayer3.position      = self.view.center;
    
    // 修改CAShapeLayer的线条相关值
    _shapeLayer3.fillColor     = [UIColor clearColor].CGColor;
    _shapeLayer3.strokeColor   = [UIColor redColor].CGColor;
    _shapeLayer3.lineWidth     = 2.f;
    
    //0 是最右侧点,0.25是最下方的点,0.5是最左侧的点,0.75是最顶端的点
    _shapeLayer3.strokeStart   = 0.f;
    _shapeLayer3.strokeEnd     = 0.f;
    
    // 建立贝塞尔曲线与CAShapeLayer之间的关联
    _shapeLayer3.path          = oval.CGPath;

    // 添加并显示
    [self.view.layer addSublayer:_shapeLayer3];
    
    // 创建定时器
    _timer = [NSTimer scheduledTimerWithTimeInterval:1.f
                                              target:self
                                            selector:@selector(animationEventTypeTwo)
                                            userInfo:nil
                                             repeats:YES];
    
    
}

/**
 *  动画效果1
 */
- (void)animationEventTypeOne {
    // 执行隐式动画
    _shapeLayer3.strokeEnd = arc4random() % 100 / 100.f;
}

/**
 *  动画效果2
 */
- (void)animationEventTypeTwo {
    CGFloat valueOne = arc4random() % 100 / 100.f;
    CGFloat valueTwo = arc4random() % 100 / 100.f;
    
    // 执行隐式动画
    _shapeLayer3.strokeStart = valueOne < valueTwo ? valueOne : valueTwo;
    _shapeLayer3.strokeEnd   = valueOne > valueTwo ? valueOne : valueTwo;
}

四   贝塞尔曲线 其他方法:

1,根据一个矩形画曲线

     + (UIBezierPath *)bezierPathWithRect:(CGRect)rect

2,根据矩形框的内切圆画曲线

+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect

3,

//以某个中心点画弧线
+ (UIBezierPath *)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;

参数:

center:弧线中心点的坐标

radius:弧线所在圆的半径

startAngle:弧线开始的角度值

endAngle:弧线结束的角度值

clockwise:是否顺时针画弧线

4,

//画二元曲线,一般和moveToPoint配合使用

- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint

参数:

endPoint:曲线的终点

controlPoint:画曲线的基准点

//以三个点画一段曲线,一般和moveToPoint配合使用

- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2

参数:

endPoint:曲线的终点

controlPoint1:画曲线的第一个基准点

controlPoint2:画曲线的第二个基准点

原文地址:https://www.cnblogs.com/developer-qin/p/4534422.html