二、CAShapLayer马步

简述

1、CAShapeLayer继承自CALayer,通过UIBezierPath的结合可以实现非drawRect方式绘制图形;
2、CAShapLayer的path是一个首尾相连的闭环曲线,即使其贝塞尔曲线是非闭环的;
3、drawRect属于CoreGraphics框架,占用cpu性能消耗较大。CAShapLayer属于CoreAnimation框架,通过GPU渲染图形不消耗内存和cpu。

CAShapLayer关键属性

//  路径
@property(nullable) CGPathRef path;
// 填充色
@property(nullable) CGColorRef fillColor;
// 描边色
@property(nullable) CGColorRef strokeColor;
// path路径开始位置  0 - 1
@property CGFloat strokeStart;
// path路径结束位置 0 - 1
@property CGFloat strokeEnd;
// 线条宽度
@property CGFloat lineWidth;
// 线条首尾外观
@property(copy) NSString *lineCap;
// 线条交接处外观
@property(copy) NSString *lineJoin;

No code no bibi

1、先来画一个对号

二、CAShapLayer马步_第1张图片
@implementation SZShapLayer

- (void)didMoveToWindow {
    CGFloat viewWidth = self.frame.size.width;
    CGFloat viewHeitht = self.frame.size.height;
    // 1、创建path
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(viewWidth / 4, viewHeitht / 2)];
    [path addLineToPoint:CGPointMake(viewWidth / 2, viewWidth / 4 * 3)];
    [path addLineToPoint:CGPointMake(viewWidth / 4 * 3, viewWidth / 3)];
    // 2、创建ShapLayer
    CAShapeLayer *shapLayer = [CAShapeLayer layer];
    shapLayer.lineWidth = 16;
    shapLayer.fillColor = [UIColor clearColor].CGColor;
    shapLayer.strokeColor = [UIColor brownColor].CGColor;
    shapLayer.path = path.CGPath;
    shapLayer.lineCap = kCALineCapRound;
    shapLayer.lineJoin = kCALineJoinRound;
    [self.layer addSublayer:shapLayer];
}

@end

这里需要注意,如果填充色非透明会是下面效果:


二、CAShapLayer马步_第2张图片

2、实现一个带动画效果的选中按钮

二、CAShapLayer马步_第3张图片
CheckAnimationButton.gif
#import 

@interface SZShapLayer : UIView
- (void)resetView;
@end
#import "SZShapLayer.h"

static NSString * const kCornerRadiusAnimationKey = @"cornerRadiusAnimation";
static NSString * const kCheckAnimationKey = @"kCheckAnimationKey";
static const CGFloat kButtonWidth = 100;
static const CGFloat kButtonHeight = 100;

@interface SZShapLayer() 

/** 对号 */
@property (nonatomic, strong) CAShapeLayer *shapeLayer;
/** 对号 */
@property (nonatomic, strong) CABasicAnimation *shapeLayerAnimation;

/** 动画进行标识 */
@property (nonatomic, assign) BOOL isAnimation;
@end

@implementation SZShapLayer

#pragma mark - Life Circle

- (instancetype)init {
    if (self = [super init]) {
        [self config];
    }
    return self;
}

-(void)layoutSubviews {
    self.layer.cornerRadius=self.frame.size.height/2;
}

#pragma mark - Outer Method 

- (void)resetView {
    if (self.isAnimation) {
        return;
    }
    self.frame = CGRectMake(100, 100, 130, 50);
    [self.shapeLayer removeFromSuperlayer];
    self.backgroundColor = [UIColor colorWithRed:0.98 green:0.81 blue:0.84 alpha:1];
}

#pragma mark - UI Build

- (void)config {
    // 1、设置self背景色
    self.backgroundColor = [UIColor colorWithRed:0.98 green:0.81 blue:0.84 alpha:1];
    // 2、添加点击手势
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
    [self addGestureRecognizer:tap];
}

- (void)showCheckAnimation {
    // 1、添加对号
    [self.layer addSublayer:self.shapeLayer];
    // 2、给对号设置动画
    [self.shapeLayer addAnimation:self.shapeLayerAnimation forKey:kCheckAnimationKey];
}

#pragma mark - Event

- (void)tap:(UITapGestureRecognizer *)tapGesture {
    if (self.isAnimation) {
        return;
    }
    self.layer.cornerRadius = kButtonHeight * 0.5;
    // 设置动画
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
    animation.delegate = self;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.duration = 0.4;
    animation.fromValue = @(self.frame.size.height * 0.5);
    [self.layer addAnimation:animation forKey:kCornerRadiusAnimationKey];
}

#pragma mark - Animation Delegate

- (void)animationDidStart:(CAAnimation *)anim {
    if ([self.layer animationForKey:kCornerRadiusAnimationKey]) {
        // 1、动画进行标识设置
        self.isAnimation = YES;
        // 2、动画设置bounds和背景色
        [UIView animateWithDuration:0.6f delay:0.0f usingSpringWithDamping:0.6f initialSpringVelocity:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.bounds = CGRectMake(0, 0, kButtonWidth, kButtonHeight);
            self.backgroundColor = [UIColor colorWithRed:1 green:0.8 blue:0.6 alpha:1];
        } completion:^(BOOL finished) {
            //[self.layer removeAnimationForKey:@"kCornerRadiusAnimationKey"];
            [self showCheckAnimation];
        }];
    } else if([self.shapeLayer animationForKey:kCheckAnimationKey]) {
        self.isAnimation = YES;
    }
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    if (self.layer.animationKeys.count == 0 && self.shapeLayer.animationKeys.count == 0) {
        self.isAnimation = NO;
    }
}

#pragma mark - Property

- (CABasicAnimation *)shapeLayerAnimation {
    if (!_shapeLayerAnimation) {
        _shapeLayerAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        _shapeLayerAnimation.delegate = self;
        _shapeLayerAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        _shapeLayerAnimation.duration = 0.4f;
        _shapeLayerAnimation.fromValue = @(0.0f);
        _shapeLayerAnimation.toValue = @(1.0f);
    }
    return _shapeLayerAnimation;
}

- (CAShapeLayer *)shapeLayer {
    if (!_shapeLayer) {
        // 1、获取宽高
        CGFloat viewWidth = self.frame.size.width;
        CGFloat viewHeitht = self.frame.size.height;
        // 2、创建path
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:CGPointMake(viewWidth / 4, viewHeitht / 2)];
        [path addLineToPoint:CGPointMake(viewWidth / 2, viewWidth / 4 * 3)];
        [path addLineToPoint:CGPointMake(viewWidth / 4 * 3, viewWidth / 3)];
        // 3、创建ShapLayer
        CAShapeLayer *shapLayer = [CAShapeLayer layer];
        shapLayer.lineWidth = 16;
        shapLayer.fillColor = [UIColor clearColor].CGColor;
        shapLayer.strokeColor = [UIColor colorWithRed:0.75 green:0.9 blue:0.9 alpha:1].CGColor;
        shapLayer.path = path.CGPath;
        shapLayer.lineCap = kCALineCapRound;
        shapLayer.lineJoin = kCALineJoinRound;
        _shapeLayer = shapLayer;
    }
    return _shapeLayer;
}

@end

这么调用

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"CAShapLayer";
    SZShapLayer *view = [SZShapLayer new];
    view.frame = CGRectMake(100, 100, 130, 50);
    self.shapView = view;
    [self.view addSubview:view];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.shapView resetView];
}

有几点需要注意:
1、static NSString * const kCornerRadiusAnimationKey = @"cornerRadiusAnimation";
这里const要在*后,表示kCornerRadiusAnimationKey这个变量的值是不可修改的。不这么写,使用该变量的地方会有警告产生:Sending 'const NSString *__strong' to parameter of type 'NSString *' discards qualifiers。
2、经过测试,animationDidStop回调函数中当所有的动画结束之后self.layer和self.shapLayer的animationKeys均为空。而非想象中的[self.shapeLayer animationForKey:kCheckAnimationKey] == anime,有兴趣的同学可以自己试试。

你可能感兴趣的:(二、CAShapLayer马步)