想必大家在加载过程中经常会遇到加载成功或者加载失败后进行一个动画提示,例如:加载完成或者加载失败变成对号或者句号。
这个方法我也是看了别人的项目,但是他的项目少了一部分代码,我这里给补上了。
下面就是这个动画的的效果
这个左面是成功动画、有面是失败动画
下面是代码,稍后我也会附上下载封装的代码
首先是AnimationView.h文件
@interface AnimationView : UIView
- (void)startSuccessAnimation;
- (void)startErrorAnimation;
@end
下面是AnimationView.m文件
#import "AnimationView.h"
#import "CCArcMoveLayer.h"
static NSString * const kName = @"name";
static CGFloat const kRadius = 20;
static CGFloat const kLineWidth = 3;
static CGFloat const kStep1Duration = 1.0;
static CGFloat const kStep2Duration = 0.5;
@interface AnimationView ()
@property (strong, nonatomic) CCArcMoveLayer *arcMoveLayer;
@property (strong, nonatomic) CAShapeLayer *checkLine;
@end
@implementation AnimationView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor whiteColor];
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(1, 1, frame.size.width - 2, frame.size.width - 2)];
view.layer.cornerRadius = (frame.size.width - 2) / 2;
[self addSubview:view];
view.backgroundColor = [UIColor clearColor];
view.layer.borderColor = [[UIColor colorWithHexString:@"#F98680"] CGColor];
view.layer.borderWidth = 1;
}
return self;
}
#pragma mark - public
- (void)startSuccessAnimation {
[self reset];
[self doSuccessStep1];
}
- (void)startErrorAnimation {
[self reset];
[self doErrorStep1];
}
#pragma mark - animation
- (void)reset {
[self.arcMoveLayer removeFromSuperlayer];
[self.checkLine removeFromSuperlayer];
}
#pragma mark - animation step stop
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
if ([[anim valueForKey:kName] isEqualToString:@"successStep1"]) {
[self doSuccessStep2];
} else if ([[anim valueForKey:kName] isEqualToString:@"errorStep1"]) {
[self doErrorStep2];
}
}
// 成功 第1阶段
- (void)doSuccessStep1 {
self.arcMoveLayer = [CCArcMoveLayer layer];
self.arcMoveLayer.contentsScale = [UIScreen mainScreen].scale;
self.arcMoveLayer.bounds = CGRectMake(0, 0, kRadius * 2 + kLineWidth, kRadius * 2 + kLineWidth);
self.arcMoveLayer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
// animation
self.arcMoveLayer.progress = 1; // end status
[self.layer addSublayer:self.arcMoveLayer];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"];
animation.duration = kStep1Duration;
animation.fromValue = @0.0;
animation.toValue = @1.0;
animation.delegate = self;
[animation setValue:@"successStep1" forKey:kName];
[self.arcMoveLayer addAnimation:animation forKey:nil];
}
#pragma mark - success
//成功 第2阶段
- (void)doSuccessStep2 {
self.checkLine = [CAShapeLayer layer];
[self.layer addSublayer:self.checkLine];
self.checkLine.frame = self.layer.bounds;
// path
UIBezierPath *path = [UIBezierPath bezierPath];
path.lineCapStyle = kCGLineCapSquare; //线条拐角
path.lineJoinStyle = kCGLineCapRound; //终点处理
[path moveToPoint:CGPointMake(CGRectGetMidX(self.bounds) - kRadius + 5, CGRectGetMidY(self.bounds))];
[path addLineToPoint:CGPointMake(CGRectGetMidX(self.bounds) - kRadius / 5, CGRectGetMidY(self.bounds) + kRadius / 5 * 2)];
[path addLineToPoint:CGPointMake(CGRectGetMidX(self.bounds) + kRadius - kRadius / 8 * 3, CGRectGetMidY(self.bounds) - kRadius / 2)];
self.checkLine.path = path.CGPath;
self.checkLine.lineWidth = kLineWidth;
self.checkLine.strokeColor = [UIColor colorWithHexString:@"#F98680"].CGColor;
self.checkLine.fillColor = nil;
//SS(strokeStart)
CGFloat SSFrom = 0;
CGFloat SSTo = 1.0;
// animation
CABasicAnimation *startAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
startAnimation.fromValue = @(SSFrom);
startAnimation.toValue = @(SSTo);
CABasicAnimation *endAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
endAnimation.fromValue = @(SSFrom);
endAnimation.toValue = @(SSTo);
CAAnimationGroup *step2 = [CAAnimationGroup animation];
step2.animations = @[endAnimation];
step2.duration = kStep2Duration;
step2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[self.checkLine addAnimation:step2 forKey:nil];
}
#pragma mark - error
- (void)doErrorStep1 {
self.arcMoveLayer = [CCArcMoveLayer layer];
self.arcMoveLayer.contentsScale = [UIScreen mainScreen].scale;
self.arcMoveLayer.bounds = CGRectMake(0, 0, kRadius * 2 + kLineWidth, kRadius * 2 + kLineWidth);
self.arcMoveLayer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
// animation
self.arcMoveLayer.progress = 1; // end status
[self.layer addSublayer:self.arcMoveLayer];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"];
animation.duration = kStep1Duration;
animation.fromValue = @0.0;
animation.toValue = @1.0;
animation.delegate = self;
[animation setValue:@"errorStep1" forKey:kName];
[self.arcMoveLayer addAnimation:animation forKey:nil];
}
#pragma mark - success
//成功 第2阶段
- (void)doErrorStep2 {
self.checkLine = [CAShapeLayer layer];
[self.layer addSublayer:self.checkLine];
self.checkLine.frame = self.layer.bounds;
// path
UIBezierPath *path = [UIBezierPath bezierPath];
path.lineCapStyle = kCGLineCapSquare; //线条拐角
path.lineJoinStyle = kCGLineCapRound; //终点处理
[path moveToPoint:CGPointMake(self.frame.size.width/4 + 3, self.frame.size.width/4 + 3 )];
CGPoint pl =CGPointMake(self.frame.size.width/4*3 - 3, self.frame.size.width/4*3 - 3);
[path addLineToPoint:pl];
[path moveToPoint:CGPointMake(self.frame.size.width/4*3 - 3, self.frame.size.width/4 + 3)];
CGPoint p2 = CGPointMake(self.frame.size.width/4.0 + 3 , self.frame.size.width/4*3 - 3);
[path addLineToPoint:p2];
self.checkLine.path = path.CGPath;
self.checkLine.lineWidth = kLineWidth;
self.checkLine.strokeColor = [UIColor colorWithHexString:@"#F98680"].CGColor;
self.checkLine.fillColor = nil;
//SS(strokeStart)
CGFloat SSFrom = 0;
CGFloat SSTo = 1.0;
// animation
CABasicAnimation *startAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
startAnimation.fromValue = @(SSFrom);
startAnimation.toValue = @(SSTo);
CABasicAnimation *endAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
endAnimation.fromValue = @(SSFrom);
endAnimation.toValue = @(SSTo);
CAAnimationGroup *step2 = [CAAnimationGroup animation];
step2.animations = @[endAnimation];
step2.duration = kStep2Duration;
step2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[self.checkLine addAnimation:step2 forKey:nil];
}
@end
下面是CCArcMoveLayer.h文件
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
@interface CCArcMoveLayer : CALayer
@property (nonatomic) CGFloat progress; // 参数
@property (nonatomic) BOOL isSuccess;
@end
下面是CCArcMoveLayer.m文件
#import "CCArcMoveLayer.h"
static CGFloat const kLineWidth = 3;
@interface CCArcMoveLayer ()
@end
@implementation CCArcMoveLayer
@dynamic progress;
+ (BOOL)needsDisplayForKey:(NSString *)key {
if ([key isEqualToString:@"progress"]) {
return YES;
}
return [super needsDisplayForKey:key];
}
- (void)drawInContext:(CGContextRef)ctx {
UIBezierPath *path = [UIBezierPath bezierPath];
CGFloat kRadius = MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)) / 2 - kLineWidth / 2;
CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
// 0
CGFloat originStart = M_PI * 3;
CGFloat originEnd = M_PI * 3;
CGFloat currentOrigin = originStart - (originStart - originEnd) * self.progress;
// D
CGFloat destStart = M_PI * 3;
CGFloat destEnd = 0;
CGFloat currentDest = destStart - (destStart - destEnd) * self.progress;
[path addArcWithCenter:center radius:kRadius startAngle:currentOrigin endAngle:currentDest clockwise:NO];
CGContextAddPath(ctx, path.CGPath);
CGContextSetLineWidth(ctx, kLineWidth);
CGContextSetStrokeColorWithColor(ctx, [UIColor colorWithHexString:@"#F98680"].CGColor);
// if (_isSuccess == YES) {
//
// } else {
// CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
// }
CGContextStrokePath(ctx);
}
@end
那如何使用呢?
_animationView = [[AnimationView alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
[_tipView addSubview:_animationView];
- (IBAction)againAction:(id)sender {
[self.animationView startSuccessAnimation];
}
- (IBAction)payFinishAction:(id)sender {
[self.animationView startErrorAnimation];
}
下载链接: