CAAnimation--CALayer

CircleView

#import <UIKit/UIKit.h>


typedef void(^ScaleCompletionHandler)();


@interface CircleView : UIView


- (instancetype) initWithFrame:(CGRect)frame andTheMaxSize:(CGFloat)maxSize theMinSize:(CGFloat)minSize theColor:(UIColor *)color;


- (void) startHeartBeat;

- (void) stopHeartBeat;


@end


#import "CircleView.h"


#pragma mark - CircleLayer class


@interface CircleLayer : CAShapeLayer


- (instancetype)initWithSuperViewFrame:(CGRect)superLayerFrame theMaxSize:(CGFloat)maxSize theMinSize:(CGFloat)minSize andTheColor:(UIColor *)color;


- (void) startAnimation;


- (void) stopAnimation;


@end


@interface CircleLayer ()


@property (nonatomic, assign) CGFloat maxSize;

@property (nonatomic, assign) CGFloat minSize;


@end


@implementation CircleLayer


- (instancetype)initWithSuperViewFrame:(CGRect)superLayerFrame theMaxSize:(CGFloat)maxSize theMinSize:(CGFloat)minSize andTheColor:(UIColor *)color {

    self = [super init];

    if (self) {

        

        self.maxSize = maxSize;

        self.minSize = minSize;

        

        self.frame = CGRectMake(superLayerFrame.size.width/2 - maxSize/2, superLayerFrame.size.height/2 - maxSize/2, maxSize, maxSize);

        UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, maxSize, maxSize)];

        self.path = circlePath.CGPath;

        self.fillColor = color.CGColor;

        self.lineWidth = 0;

        

    }

    return self;

}


#pragma mark Public methods


- (void)startAnimation {

    [self performScaleAnimation];

}


- (void)stopAnimation {

    [self removeAllAnimations];

}


#pragma mark Private methods


- (void) performScaleAnimation {

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];

    animation.keyTimes = @[@0, @0.5, @1];

    animation.values = @[@(self.maxSize / self.maxSize), @(self.minSize / self.maxSize), @(self.maxSize / self.maxSize)];

    animation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];

    animation.repeatCount = HUGE;

    animation.duration = 1.0;

    [self addAnimation:animation forKey:animation.keyPath];

}


@end



#pragma mark - WireLayer class


@interface WireLayer : CAShapeLayer


- (instancetype) initWithSuperLayerFrame:(CGRect)superLayerFrame

                              theMaxSize:(CGFloat)maxSize

                              theMinSize:(CGFloat)minSize theStartAngle:(CGFloat)startAngle theEndAngle:(CGFloat)endAngle

                             andTheColor:(UIColor *)color;


- (void) startAnimationWithStartAngle:(CGFloat)startAngle andEndAngle:(CGFloat)endAngle;


- (void) stopAnimation;


@end


@interface WireLayer ()


@property (nonatomic, assign) CGFloat maxSize;

@property (nonatomic, assign) CGFloat minSize;


@end


@implementation WireLayer


#pragma mark Override


- (instancetype)initWithSuperLayerFrame:(CGRect)superLayerFrame

                             theMaxSize:(CGFloat)maxSize

                             theMinSize:(CGFloat)minSize theStartAngle:(CGFloat)startAngle theEndAngle:(CGFloat)endAngle

                            andTheColor:(UIColor *)color {

    self = [super init];

    if (self) {

        

        self.maxSize = maxSize * 1.6;

        self.minSize = minSize * 2.3;

        

        self.frame = CGRectMake(superLayerFrame.size.width/2 - self.maxSize/2, superLayerFrame.size.height/2 - self.maxSize/2, self.maxSize, self.maxSize);

        UIBezierPath *wire = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2) radius:self.maxSize / 2 startAngle:startAngle endAngle:endAngle clockwise:YES];

        self.path = wire.CGPath;

        self.fillColor = nil;

        self.strokeColor = color.CGColor;

        self.lineWidth = 2.5;

        self.backgroundColor = [UIColor clearColor].CGColor;

        

    }

    return self;

}


#pragma mark Public methods


- (void)startAnimationWithStartAngle:(CGFloat)startAngle andEndAngle:(CGFloat)endAngle {

    [self performScaleAndRotationAnimationWithStartAngle:startAngle EndAngle:endAngle];

}


- (void)stopAnimation {

    [self removeAllAnimations];

}


#pragma mark Private methods


- (void) performScaleAndRotationAnimationWithStartAngle:(CGFloat)startAngle EndAngle:(CGFloat)endAngle {

    CAKeyframeAnimation *scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];

    scaleAnimation.keyTimes = @[@0, @0.5, @1];

    scaleAnimation.values = @[@(self.maxSize / self.maxSize), @(self.minSize / self.maxSize), @(self.maxSize / self.maxSize)];

    scaleAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];

    

    CAKeyframeAnimation *rotationAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];

    rotationAnimation.keyTimes = @[@0, @0.5, @1];

    rotationAnimation.values = @[@(startAngle), @(endAngle), @(startAngle + 2*M_PI)];

    rotationAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];

    

    CAAnimationGroup *group = [CAAnimationGroup animation];

    group.animations = @[rotationAnimation, scaleAnimation];

    group.duration = 1.0;

    group.repeatCount = HUGE;

    

    [self addAnimation:group forKey:@"group"];

    

}


@end



#pragma mark - CircleView @implementation


@interface CircleView ()


@property (nonatomic, strong) CircleLayer *circleLayer;

@property (nonatomic, strong) WireLayer *topWireLayer;

@property (nonatomic, strong) WireLayer *bottomWireLayer;


@end


@implementation CircleView


#pragma mark Override


- (instancetype)initWithFrame:(CGRect)frame andTheMaxSize:(CGFloat)maxSize theMinSize:(CGFloat)minSize theColor:(UIColor *)color {

    self = [super initWithFrame:frame];

    if (self) {

        

        self.circleLayer = [[CircleLayer alloc] initWithSuperViewFrame:self.bounds theMaxSize:maxSize theMinSize:minSize andTheColor:color];

        [self.layer addSublayer:self.circleLayer];


        self.topWireLayer = [[WireLayer alloc] initWithSuperLayerFrame:self.bounds theMaxSize:maxSize theMinSize:minSize theStartAngle:(M_PI + M_PI_4) theEndAngle:(2*M_PI - M_PI_4) andTheColor:color];

        [self.layer addSublayer:self.topWireLayer];

        

        self.bottomWireLayer = [[WireLayer alloc] initWithSuperLayerFrame:self.bounds theMaxSize:maxSize theMinSize:minSize theStartAngle:(M_PI_4) theEndAngle:(M_PI_2 + M_PI_4) andTheColor:color];

        [self.layer addSublayer:self.bottomWireLayer];

        

    }

    return self;

}


#pragma mark Public methods


- (void)startHeartBeat {

    [self.circleLayer startAnimation];

    [self.topWireLayer startAnimationWithStartAngle:(0) andEndAngle:(M_PI)];

    [self.bottomWireLayer startAnimationWithStartAngle:(0) andEndAngle:(M_PI)];                         // 以自己的角度坐标为标准

}


- (void)stopHeartBeat {

    [self.circleLayer stopAnimation];

    [self.topWireLayer stopAnimation];

    [self.bottomWireLayer stopAnimation];

}


@end


GrilleView

#import <UIKit/UIKit.h>


@interface GrilleView : UIView


- (instancetype) initWithFrame:(CGRect)frame theMaxSize:(CGFloat)maxSize theMinSize:(CGFloat)minSize andTheGrilleColor:(UIColor *)color;


- (void) startWave;


- (void) stopWave;


@end

#import "GrilleView.h"

#import "Utils.h"


#pragma mark - GrilleLayer class


@interface GrilleLayer : CAShapeLayer


- (instancetype) initWithFrame:(CGRect)frame maxSize:(CGFloat)maxSize minSize:(CGFloat)minSize andTheColor:(UIColor *)color;


- (void) makeExpansion;


- (void) stopExpansion;


@end


@interface GrilleLayer ()


@property (nonatomic, assign) CGFloat maxSize;

@property (nonatomic, assign) CGFloat minSize;


@end


@implementation GrilleLayer


#pragma mark Override


- (instancetype)initWithFrame:(CGRect)frame maxSize:(CGFloat)maxSize minSize:(CGFloat)minSize andTheColor:(UIColor *)color {

    self = [super init];

    if (self) {

        

        self.maxSize = maxSize;

        self.minSize = minSize;

        

        self.frame = frame;

        self.backgroundColor = [UIColor clearColor].CGColor;

        UIBezierPath *path = [UIBezierPath bezierPath];

        [path moveToPoint:CGPointMake(frame.size.width/2, frame.size.height - (frame.size.height/2 - minSize/2))];

        [path addLineToPoint:CGPointMake(frame.size.width/2, frame.size.height/2 - minSize/2)];

        self.path = path.CGPath;

        self.strokeColor = color.CGColor;

        self.lineWidth = 6.0;

        self.lineCap = kCALineCapSquare;

        

    }

    return self;

}


#pragma mark Public method


- (void)makeExpansion {

    CAKeyframeAnimation *expansionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.y"];

    expansionAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];

    expansionAnimation.keyTimes = @[@0, @0.45, @0.9];

    expansionAnimation.values = @[@(self.minSize / self.minSize), @(self.maxSize / self.minSize), @(self.minSize / self.minSize)];

    expansionAnimation.duration = 0.9;

    expansionAnimation.repeatCount = HUGE;

    [self addAnimation:expansionAnimation forKey:expansionAnimation.keyPath];

}


- (void)stopExpansion {

    [self removeAllAnimations];

}


@end


#pragma mark -GrilleView @implementation


@interface GrilleView ()


@property (nonatomic, copy) NSArray *grilles;

@property (nonatomic, assign) NSTimeInterval timeInterval;


@end


@implementation GrilleView


#pragma mark Override


- (instancetype)initWithFrame:(CGRect)frame theMaxSize:(CGFloat)maxSize theMinSize:(CGFloat)minSize andTheGrilleColor:(UIColor *)color {

    self = [super initWithFrame:frame];

    if (self) {

        

        self.timeInterval = 0.0f;

        CGFloat margin = 6.0f;

        

        GrilleLayer *grille_mid = [[GrilleLayer alloc] initWithFrame:CGRectMake(self.frame.size.width/2 - margin/2, self.frame.size.height/2 - maxSize/2, margin, maxSize) maxSize:maxSize minSize:minSize andTheColor:color];

        GrilleLayer *grille_left_one = [[GrilleLayer alloc] initWithFrame:CGRectMake(grille_mid.frame.origin.x - 4*margin, grille_mid.frame.origin.y, margin, maxSize) maxSize:maxSize minSize:minSize andTheColor:color];

        GrilleLayer *grille_left_two = [[GrilleLayer alloc] initWithFrame:CGRectMake(grille_mid.frame.origin.x - 2*margin, grille_mid.frame.origin.y, margin, maxSize) maxSize:maxSize minSize:minSize andTheColor:color];

        GrilleLayer *grille_right_two = [[GrilleLayer alloc] initWithFrame:CGRectMake(grille_mid.frame.origin.x + 2*margin, grille_mid.frame.origin.y, margin, maxSize) maxSize:maxSize minSize:minSize andTheColor:color];

        GrilleLayer *grille_right_one = [[GrilleLayer alloc] initWithFrame:CGRectMake(grille_mid.frame.origin.x + 4*margin, grille_mid.frame.origin.y, margin, maxSize) maxSize:maxSize minSize:minSize andTheColor:color];

        

        self.grilles = @[grille_left_one, grille_left_two, grille_mid, grille_right_two, grille_right_one];

        [self.grilles enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

            [self.layer addSublayer:(GrilleLayer *)obj];

        }];

        

    }

    return self;

}


#pragma mark Public methods


- (void)startWave {

    [self.grilles enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

        GrilleLayer *grille = (GrilleLayer *)obj;

        delay(self.timeInterval, ^{

            [grille makeExpansion];

        });

        self.timeInterval += 0.15;

    }];

}


- (void)stopWave {

    [self.grilles enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

        GrilleLayer *grille = (GrilleLayer *)obj;

        [grille stopExpansion];

    }];

}


@end




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值