IOS仿最新版愛奇異loading動畫

愛奇異更新版本之後,那個loading效果比較簡潔,卻又不失美觀,遂仿製一把,以供廣大程序員交流學習,效果圖如下,


效果圖中是垂直效果,但只要在路徑那裏改一下即可,還有一個縮放動畫未添加,留給看官們自己處理大笑大笑


動畫分析:

圓弧動畫:UIBezierPath +CAShapeLayer 

 其中UIBezierPath畫出左右2邊的圓弧,然後用基本動畫的storkEnd或storkStart來驅動即可,達到動畫效果

代碼如下:


 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.duration = 0.7f;
    animation.fromValue = @(1);
    animation.toValue = @(0.0);
    //animation.delegate = self;
    //animation.repeatCount = MAXFLOAT;
    
    // 保持動畫結束時的狀態
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [animation setValue:@"arcRotateAnim" forKey:@"animationName"];
    
    [self.leftArcLayer addAnimation:animation forKey:@""];
    [self.rightArcLayer addAnimation:animation forKey:@""];
    
    
    //畫布旋轉動畫
    CABasicAnimation *BasicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    
    BasicAnimation.toValue=@(M_PI*2);
    BasicAnimation.duration= 0.7;
    
    //BasicAnimation.delegate=self;
    [BasicAnimation setValue:@"BasicAnimationRotation" forKey:@"animationName"];
    [self.layer removeAllAnimations];
    [self.layer addAnimation:BasicAnimation forKey:@"BasicAnimationRotation"];



圖層分析 :CAShapeLayer在強大之處這裏不細說,本案例中主要有4個圖層 ,分別使用懶加載實現,代碼如下:



/**
 重寫get屬性

 @return CAShapeLayer
 */
-(CAShapeLayer*) leftArcLayer{


    if (!_leftArcLayer) {
        _leftArcLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
        
        UIBezierPath *path = [UIBezierPath bezierPath];
        
        [path addArcWithCenter:center radius:25 startAngle: -PI / 2 endAngle:PI / 2 clockwise:YES];
        
        
        _leftArcLayer.borderColor = [UIColor blackColor].CGColor;
        _leftArcLayer.lineWidth = 1.f;
        _leftArcLayer.path = path.CGPath;
        _leftArcLayer.fillColor = [UIColor clearColor].CGColor;
        _leftArcLayer.strokeColor = [UIColor greenColor].CGColor;
    }
    return _leftArcLayer;
    
}


-(CAShapeLayer*) rightArcLayer{
    
    
    if (!_rightArcLayer) {
        _rightArcLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
        
        UIBezierPath *path = [UIBezierPath bezierPath];
        
        [path addArcWithCenter:center radius:25 startAngle: PI / 2 endAngle:-PI / 2 clockwise:YES];
        
        
        _rightArcLayer.borderColor = [UIColor blackColor].CGColor;
        _rightArcLayer.lineWidth = 1.f;
        _rightArcLayer.path = path.CGPath;
        _rightArcLayer.fillColor = [UIColor clearColor].CGColor;
        _rightArcLayer.strokeColor = [UIColor greenColor].CGColor;
    }
    return _rightArcLayer;
    
}


-(CAShapeLayer*) leftPointLayer{

    if (!_leftPointLayer) {
        _leftPointLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);

        _leftPointLayer.bounds = CGRectMake(0, 0, 2, 2);
        _leftPointLayer.position = center;
        _leftPointLayer.backgroundColor = [UIColor greenColor].CGColor;
    }
    return _leftPointLayer;
}

-(CAShapeLayer*) rightPointLayer{
    
    if (!_rightPointLayer) {
        _rightPointLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
        _rightPointLayer.bounds = CGRectMake(0, 0, 2, 2);
        _rightPointLayer.position = center;
        _rightPointLayer.backgroundColor = [UIColor greenColor].CGColor;
    }
    return _rightPointLayer;
}



圓點動畫:基本動畫中的位移動畫:代碼如下:

-(void) middlePointMoveAnim{

    CABasicAnimation *moveAnim = [CABasicAnimation animationWithKeyPath:@"position"];
    CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
    moveAnim.fromValue = [NSValue valueWithCGPoint:center];
    moveAnim.toValue = [NSValue valueWithCGPoint:CGPointMake(center.x , center.y  - 25)];
    moveAnim.duration = 0.5f;
    moveAnim.delegate = self;
    
    moveAnim.fillMode = kCAFillModeForwards;
    moveAnim.removedOnCompletion = NO;
    
    moveAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    
    //[self.leftPointLayer removeAllAnimations];
    [moveAnim setValue:@"positionAnimation" forKey:@"moveAnim"];
    [self.leftPointLayer addAnimation:moveAnim forKey:@""];
    
    
    
    CABasicAnimation *moveRightAnim = [CABasicAnimation animationWithKeyPath:@"position"];
   
    moveRightAnim.fromValue = [NSValue valueWithCGPoint:center];
    moveRightAnim.toValue = [NSValue valueWithCGPoint:CGPointMake(center.x , center.y  + 25)];
    moveRightAnim.duration = 0.5f;
    //moveRightAnim.delegate = self;
    moveRightAnim.fillMode = kCAFillModeForwards;
    moveRightAnim.removedOnCompletion = NO;
    moveRightAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    //[self.rightPointLayer removeAllAnimations];
    [self.rightPointLayer addAnimation:moveRightAnim forKey:@""];

}





全部代碼如下:

.h文件


@interface ShapeLayer_BezierParh : UIView<CAAnimationDelegate>

@property(nonatomic,strong) CAShapeLayer* leftArcLayer;
@property(nonatomic,strong) CAShapeLayer* rightArcLayer;

@property(nonatomic,strong) CAShapeLayer* leftPointLayer;
@property(nonatomic,strong) CAShapeLayer* rightPointLayer;

-(void) startAnim;

-(void) middlePointMoveAnim;

@end

.m文件:

#import "ShapeLayer_BezierParh.h"

#define PI 3.1415926

@implementation ShapeLayer_BezierParh


-(instancetype) initWithFrame:(CGRect)frame{

    if (self = [super initWithFrame:frame]) {
        
        [self.layer addSublayer:self.leftArcLayer];
        [self.layer addSublayer:self.rightArcLayer];
        [self.layer addSublayer:self.leftPointLayer];
        [self.layer addSublayer:self.rightPointLayer];
    }
    
    return self;

}


/**
 重寫get屬性

 @return CAShapeLayer
 */
-(CAShapeLayer*) leftArcLayer{


    if (!_leftArcLayer) {
        _leftArcLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
        
        UIBezierPath *path = [UIBezierPath bezierPath];
        
        [path addArcWithCenter:center radius:25 startAngle: -PI / 2 endAngle:PI / 2 clockwise:YES];
        
        
        _leftArcLayer.borderColor = [UIColor blackColor].CGColor;
        _leftArcLayer.lineWidth = 1.f;
        _leftArcLayer.path = path.CGPath;
        _leftArcLayer.fillColor = [UIColor clearColor].CGColor;
        _leftArcLayer.strokeColor = [UIColor greenColor].CGColor;
    }
    return _leftArcLayer;
    
}


-(CAShapeLayer*) rightArcLayer{
    
    
    if (!_rightArcLayer) {
        _rightArcLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
        
        UIBezierPath *path = [UIBezierPath bezierPath];
        
        [path addArcWithCenter:center radius:25 startAngle: PI / 2 endAngle:-PI / 2 clockwise:YES];
        
        
        _rightArcLayer.borderColor = [UIColor blackColor].CGColor;
        _rightArcLayer.lineWidth = 1.f;
        _rightArcLayer.path = path.CGPath;
        _rightArcLayer.fillColor = [UIColor clearColor].CGColor;
        _rightArcLayer.strokeColor = [UIColor greenColor].CGColor;
    }
    return _rightArcLayer;
    
}


-(CAShapeLayer*) leftPointLayer{

    if (!_leftPointLayer) {
        _leftPointLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);

        _leftPointLayer.bounds = CGRectMake(0, 0, 2, 2);
        _leftPointLayer.position = center;
        _leftPointLayer.backgroundColor = [UIColor greenColor].CGColor;
    }
    return _leftPointLayer;
}

-(CAShapeLayer*) rightPointLayer{
    
    if (!_rightPointLayer) {
        _rightPointLayer = [CAShapeLayer layer];
        CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
        _rightPointLayer.bounds = CGRectMake(0, 0, 2, 2);
        _rightPointLayer.position = center;
        _rightPointLayer.backgroundColor = [UIColor greenColor].CGColor;
    }
    return _rightPointLayer;
}


-(void) startAnim{
    
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.duration = 0.7f;
    animation.fromValue = @(1);
    animation.toValue = @(0.0);
    //animation.delegate = self;
    //animation.repeatCount = MAXFLOAT;
    
    // 保持動畫結束時的狀態
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [animation setValue:@"arcRotateAnim" forKey:@"animationName"];
    
    [self.leftArcLayer addAnimation:animation forKey:@""];
    [self.rightArcLayer addAnimation:animation forKey:@""];
    
    
    //畫布旋轉動畫
    CABasicAnimation *BasicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    
    BasicAnimation.toValue=@(M_PI*2);
    BasicAnimation.duration= 0.7;
    
    //BasicAnimation.delegate=self;
    [BasicAnimation setValue:@"BasicAnimationRotation" forKey:@"animationName"];
    [self.layer removeAllAnimations];
    [self.layer addAnimation:BasicAnimation forKey:@"BasicAnimationRotation"];

    
    
    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC));
    dispatch_after(delayTime, dispatch_get_main_queue(), ^{
        [self middlePointMoveAnim];
        
    });

}

-(void) middlePointMoveAnim{

    CABasicAnimation *moveAnim = [CABasicAnimation animationWithKeyPath:@"position"];
    CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
    moveAnim.fromValue = [NSValue valueWithCGPoint:center];
    moveAnim.toValue = [NSValue valueWithCGPoint:CGPointMake(center.x , center.y  - 25)];
    moveAnim.duration = 0.5f;
    moveAnim.delegate = self;
    
    moveAnim.fillMode = kCAFillModeForwards;
    moveAnim.removedOnCompletion = NO;
    
    moveAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    
    //[self.leftPointLayer removeAllAnimations];
    [moveAnim setValue:@"positionAnimation" forKey:@"moveAnim"];
    [self.leftPointLayer addAnimation:moveAnim forKey:@""];
    
    
    
    CABasicAnimation *moveRightAnim = [CABasicAnimation animationWithKeyPath:@"position"];
   
    moveRightAnim.fromValue = [NSValue valueWithCGPoint:center];
    moveRightAnim.toValue = [NSValue valueWithCGPoint:CGPointMake(center.x , center.y  + 25)];
    moveRightAnim.duration = 0.5f;
    //moveRightAnim.delegate = self;
    moveRightAnim.fillMode = kCAFillModeForwards;
    moveRightAnim.removedOnCompletion = NO;
    moveRightAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    //[self.rightPointLayer removeAllAnimations];
    [self.rightPointLayer addAnimation:moveRightAnim forKey:@""];

}

-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{

    if([[anim valueForKey:@"animationName"] isEqualToString:@"arcRotateAnim"]){
    
        NSLog(@"144----------------arcRotateAnim:stop  %d",flag);
       
        if(flag){
            dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC));
            dispatch_after(delayTime, dispatch_get_main_queue(), ^{
               [self middlePointMoveAnim];
                
            });
        }
        
        
        
        
    }
    else if([[anim valueForKey:@"moveAnim"] isEqualToString:@"positionAnimation"]){
    
        NSLog(@"171----------------moveAnim:stop  :%d",flag);
        
        if(flag){
            dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC));
            dispatch_after(delayTime, dispatch_get_main_queue(), ^{
                [self startAnim];
            });

        }
        
    }

}


@end



在vc中的測試代碼如下:

-(void) testShapeLayer{

    
   self.bezierParhLayer = [[ShapeLayer_BezierParh alloc] initWithFrame:CGRectMake((CGRectGetWidth(self.view.frame) / 2) - 25, 100, 100, 100)];

    //self.bezierParhLayer.backgroundColor = [UIColor wh];
    
    [self.view addSubview:self.bezierParhLayer];
    
   
}

將開啓動畫放在一個按鈕下,點擊按鈕進行動畫啓動:

[self.bezierParhLayer middlePointMoveAnim];



其中屬性:

@property(nonatomic,strong) ShapeLayer_BezierParh* bezierParhLayer;


發佈了151 篇原創文章 · 獲贊 10 · 訪問量 49萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章