二、CAShapLayer马步

<h4>简述</h4>

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

<h4>CAShapLayer关键属性</h4>

//  路径
@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;

<h4>No code no bibi</h4>

<h5>1、先来画一个对号</h5>

@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

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


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

CheckAnimationButton.gif
#import <UIKit/UIKit.h>

@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() <CAAnimationDelegate>

/** 对号 */
@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<UITouch *> *)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,有兴趣的同学可以自己试试。

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

推荐阅读更多精彩内容