iOS-CAShapeLayer实战

login.gif

源代码

项目的小动画基于CAShapeLayer与CABasicAnimation。

将界面分为三个模块介绍

  • 渐变的背景色
    利用CAGradientLayer实现渐变背景色
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.frame  = self.view.bounds;
    gradientLayer.colors = @[
                             (__bridge id)[UIColor purpleColor].CGColor,
                             (__bridge id)[UIColor redColor].CGColor,
                             (__bridge id)[UIColor blueColor].CGColor
                             ];
    gradientLayer.startPoint = CGPointMake(0.5, 0);
    gradientLayer.endPoint   = CGPointMake(0.5, 1);
    gradientLayer.locations  = @[@0.3,@0.7,@1];
    [self.view.layer addSublayer:gradientLayer];

  • 带动画的textfield
    监听文字长度的变化,利用animateWithDuration改变位置。

#import <UIKit/UIKit.h>

@interface ICETextField : UIView

@property (nonatomic, strong) NSString *strPlaceHolder;
@property (nonatomic, strong) UITextField *tfdICE;

@end
//
//  ICETextField.m
//  ICELogin
//
//  Created by iOS on 1/4/17.
//  Copyright © 2017年 iOS. All rights reserved.
//

#import "ICETextField.h"
@interface ICETextField ()
<
 UITextFieldDelegate
>
@property (nonatomic, strong) UILabel *lblPlaceHolder;
@property (nonatomic, assign) BOOL isUp;//yes表示placeholder在tfd上面
@end
@implementation ICETextField

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.isUp = NO;
        [self createView];
    }
    return self;
}

- (void)setStrPlaceHolder:(NSString *)strPlaceHolder {
    _strPlaceHolder = strPlaceHolder;
    self.lblPlaceHolder.text = strPlaceHolder;
}

- (UITextField *)tfdICE {
    if (!_tfdICE) {
        _tfdICE = [[UITextField alloc]initWithFrame:CGRectZero];
        _tfdICE.delegate = self;
        [self addSubview:_tfdICE];
    }
    return _tfdICE;
}

- (UILabel *)lblPlaceHolder {
    if (!_lblPlaceHolder) {
        self.lblPlaceHolder           = [[UILabel alloc]init];
        self.lblPlaceHolder.textColor = [UIColor grayColor];
        self.lblPlaceHolder.font = [UIFont systemFontOfSize:15];
        _lblPlaceHolder.text = self.strPlaceHolder;
        [self addSubview:self.lblPlaceHolder];
    }
    return _lblPlaceHolder;
}

- (void)createView {
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(p_TextFieldLengthChange:) name:UITextFieldTextDidChangeNotification object:self.tfdICE];
    [self.lblPlaceHolder class];
    
    UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, CGRectGetHeight(self.frame)-1, CGRectGetWidth(self.frame), 1)];
    view.backgroundColor = [UIColor whiteColor];
    [self addSubview:view];
}


-(void)layoutSubviews {
    [super layoutSubviews];
    self.tfdICE.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)-1);
    self.lblPlaceHolder.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)-1);
}

/**
 监听tfd长度改变

 @param sender sender
 */
- (void)p_TextFieldLengthChange:(UITextField *)sender {
    [self p_movelblAnimation];
}


- (void)p_movelblAnimation {
    if (_tfdICE.text.length == 0 && _isUp) {
        //下移动
        [self p_ChangeFrameWithBool:YES];
    }
    else if (_tfdICE.text.length != 0 && !_isUp) {
        //上移动
        [self p_ChangeFrameWithBool:NO];
    }
}

- (void)p_ChangeFrameWithBool:(BOOL)isTurnDown {
    NSLog(@"%@",NSStringFromCGPoint(self.lblPlaceHolder.center));
    
    typeof(self) __weak weakSelf=self;
    if (isTurnDown) {
        //下移动
        [UIView animateWithDuration:0.2 animations:^{
            CGPoint point = weakSelf.lblPlaceHolder.center;
            point.y = point.y + 20;
            weakSelf.lblPlaceHolder.center = point;
            weakSelf.isUp = NO;
        }];
    }
    else {
        //上移动
        [UIView animateWithDuration:0.2 animations:^{
            CGPoint point = weakSelf.lblPlaceHolder.center;
            point.y = point.y - 20;
            weakSelf.lblPlaceHolder.center = point;
            weakSelf.isUp = YES;
        }];
    }
    NSLog(@"%@",NSStringFromCGPoint(self.lblPlaceHolder.center));
}

@end

  • 按钮的动画效果
#import <UIKit/UIKit.h>
typedef void(^ICEBlock)();

@interface ICEButton : UIButton

@property (nonatomic,copy) ICEBlock translateBlock;

@end
//
//  ICEButton.m
//  ICELogin
//
//  Created by iOS on 1/4/17.
//  Copyright © 2017年 iOS. All rights reserved.
//

#import "ICEButton.h"
@interface ICEButton ()

@property (nonatomic, strong) UIButton *button;

//拉升透明的masklayer
@property (nonatomic,strong) CAShapeLayer *maskLayer;

//view底层的椭圆边框
@property (nonatomic,strong) CAShapeLayer *shapeLayer;

//loading layer
@property (nonatomic,strong) CAShapeLayer *loadingLayer;

//点击按钮后的layer
@property (nonatomic,strong) CAShapeLayer *clickCicrleLayer;


@end

@implementation ICEButton
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self drawMask:frame.size.height/2];
        
        [self.layer addSublayer:self.maskLayer];
        
        [self createDefaultBtn];
    }
    return self;
}


/**
 画椭圆边框
 
 @param height 高度
 */
- (void)drawMask:(CGFloat)height {
    _shapeLayer             = [CAShapeLayer layer];
    _shapeLayer.frame       = self.bounds;
    _shapeLayer.path        = [self drawBezierPath:height].CGPath;
    _shapeLayer.fillColor   = [UIColor clearColor].CGColor;
    _shapeLayer.strokeColor = [UIColor whiteColor].CGColor;
    _shapeLayer.lineWidth   = 2;
    [self.layer addSublayer:_shapeLayer];
}

/**
 创建按钮
 */
- (void) createDefaultBtn{
    _button                 = [UIButton buttonWithType:UIButtonTypeCustom];
    _button.frame           = self.bounds;
    _button.titleLabel.font = [UIFont systemFontOfSize:13.f];

    [_button setTitle:@"登陆"
             forState:UIControlStateNormal];
    [_button setTitleColor:[UIColor whiteColor]
                  forState:UIControlStateNormal];
    [self addSubview:_button];
    [_button addTarget:self
                action:@selector(didPressedToClickBtn:)
      forControlEvents:UIControlEventTouchUpInside];
}


/**
 点击按钮触发事件

 @param sender sender
 */
- (void)didPressedToClickBtn:(UIButton *)sender {
    //将要出现的盖在button上的layer
    _maskLayer.opacity            = 0.5;
    CABasicAnimation *animation   = [CABasicAnimation animationWithKeyPath:@"path"];
    animation.duration            = 0.25;
    animation.toValue             = (__bridge id _Nullable)([self drawBezierPath:self.frame.size.height/2].CGPath);
    animation.fillMode            = kCAFillModeForwards;
    animation.removedOnCompletion = NO;
    [_maskLayer addAnimation:animation forKey:@"maskAnimation"];
    
    [self performSelector:@selector(dismissAnimation) withObject:self afterDelay:animation.duration+0.2];
}



//登录按钮合拢并消失(透明)
-(void)dismissAnimation{
    [self removeSubViews];
    
    CAAnimationGroup *animationGroup    = [CAAnimationGroup animation];
    CABasicAnimation *basicAnimation    = [CABasicAnimation animationWithKeyPath:@"path"];
    basicAnimation.duration             = 0.2;
    basicAnimation.toValue              = (__bridge id _Nullable)([self drawBezierPath:self.frame.size.width/2].CGPath);
    basicAnimation.removedOnCompletion  = NO;
    basicAnimation.fillMode             = kCAFillModeForwards;
    
    CABasicAnimation *basicAnimation1   = [CABasicAnimation animationWithKeyPath:@"opacity"];
    basicAnimation1.beginTime           = 0.10;
    basicAnimation1.duration            = 0.2;
    basicAnimation1.toValue             = @0;
    basicAnimation1.fillMode            = kCAFillModeForwards;
    basicAnimation1.removedOnCompletion = NO;
    animationGroup.removedOnCompletion  = NO;
    animationGroup.fillMode             = kCAFillModeForwards;
    animationGroup.animations           = @[
                                            basicAnimation,
                                            basicAnimation1
                                            ];
    animationGroup.duration             = basicAnimation1.beginTime + basicAnimation1.duration;
    [_shapeLayer addAnimation:animationGroup forKey:@"dismissAnimation"];
    
    [self performSelector:@selector(loadingAnimation) withObject:self afterDelay:animationGroup.duration];
}


//菊花
-(void)loadingAnimation{
    CGFloat radius            = self.bounds.size.height/2 - 3;
    UIBezierPath *bezierPath  = [UIBezierPath bezierPath];
    [bezierPath addArcWithCenter:CGPointMake(0,0) radius:radius startAngle:M_PI/2 endAngle:M_PI/2+M_PI/2 clockwise:YES];
    
    _loadingLayer             = [CAShapeLayer layer];
    _loadingLayer.position    = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
    _loadingLayer.fillColor   = [UIColor clearColor].CGColor;
    _loadingLayer.strokeColor = [UIColor whiteColor].CGColor;
    _loadingLayer.lineWidth   = 2;
    _loadingLayer.path        = bezierPath.CGPath;
    [self.layer addSublayer:_loadingLayer];
    
    
    CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    basicAnimation.fromValue         = @(0);
    basicAnimation.toValue           = @(M_PI*2);
    basicAnimation.duration          = 0.5;
    basicAnimation.repeatCount       = LONG_MAX;
    [_loadingLayer addAnimation:basicAnimation forKey:@"loadingAnimation"];
    
    [self performSelector:@selector(removeAllAnimation) withObject:self afterDelay:2];
}



//画一个位于view中间直径是view高的一个圆,透明度为0
-(CAShapeLayer *)maskLayer {
    if(!_maskLayer){
        _maskLayer           = [CAShapeLayer layer];
        _maskLayer.opacity   = 0;
        _maskLayer.fillColor = [UIColor whiteColor].CGColor;
        _maskLayer.path      = [self drawBezierPath:self.frame.size.width/2].CGPath;
    }
    return _maskLayer;
}


//
-(UIBezierPath *)drawBezierPath:(CGFloat)x{
    CGFloat radius = self.bounds.size.height/2 - 3;
    CGFloat right  = self.bounds.size.width-x;
    CGFloat left   = x;
    
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    bezierPath.lineJoinStyle = kCGLineJoinRound;
    bezierPath.lineCapStyle  = kCGLineCapRound;
    //右边圆弧
    [bezierPath addArcWithCenter:CGPointMake(right, self.bounds.size.height/2) radius:radius startAngle:-M_PI/2 endAngle:M_PI/2 clockwise:YES];
    //左边圆弧
    [bezierPath addArcWithCenter:CGPointMake(left, self.bounds.size.height/2) radius:radius startAngle:M_PI/2 endAngle:-M_PI/2 clockwise:YES];
    //闭合弧线
    [bezierPath closePath];
    
    return bezierPath;
}

/**
 移除按钮 layer
 */
-(void)removeSubViews{
    [_button removeFromSuperview];
    [_maskLayer removeFromSuperlayer];
    [_loadingLayer removeFromSuperlayer];
    [_clickCicrleLayer removeFromSuperlayer];
}

-(void)removeAllAnimation{
    [self removeSubViews];
    if(self.translateBlock){
        self.translateBlock();
    }
}

@end

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

推荐阅读更多精彩内容