心路简介
在CoreAnimation
中有fromValue
和toValue
我就在想,如果把这个东西放到Label上,让label的文字跟随数字的变化而变化,这样变化的Label不就出来了吗。
一、动画设计
CoreAnimation
是添加到layer上的,所以需要先创建一个自定义的WYCountingLayer
,要跟随数字而变化,所以我增加了一个 wy_number
属性,并且使用@dynamic
修饰该属性。
1.想要在属性改变的时候重绘,需要重写needsDisplayForKey:
当layer的属性发生改变的时候就会通过这个方法询问是否需要对当前layer进行重绘。
NSString *const WYAnimationKey = @"wy_number";
+ (BOOL)needsDisplayForKey:(NSString *)key {
if ([key isEqualToString:WYAnimationKey]) {
return YES;
}
return [super needsDisplayForKey:key];
}
2.为wy_number
增加CABasicAnimation
,这样当wy_number
发生改变的时候就会有动画效果了,layer的隐式动画的实现原理就是这样的
- (id<CAAction>)actionForKey:(NSString *)event {
if (self.presentationLayer) {
if ([event isEqualToString:WYAnimationKey]) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:WYAnimationKey];
animation.fromValue = [self.presentationLayer valueForKey:WYAnimationKey];
return animation;
}
}
return [super actionForKey:event];
}
3.创建一个WYCountingLabel
的类并且有一个wy_number
的属性
@interface WYCountingLabel()
@property (nonatomic, strong) WYCountingLayer *countingLayer;
@end
@implementation WYCountingLabel
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupLayer];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self setupLayer];
}
- (void)setupLayer {
// 一定要给countingLayer设置frame并且添加到label的layer上
// 否则countingLayer的drawInContex:方法是不会走的
self.countingLayer = [WYCountingLayer layer];
self.countingLayer.ownerLabel = self;
self.countingLayer.frame = self.bounds;
[self.layer addSublayer:_countingLayer];
}
- (void)setWy_number:(double)wy_number {
_wy_number = wy_number;
self.countingLayer.wy_number = wy_number;
}
4.重写WYCountingLayer
的drawInContex:
方法,在这个方法中更新label
- (void)drawInContext:(CGContextRef)ctx {
[self.ownerLabel wy_updateLabelText:self.wy_number];
}
二、项目中使用
只需要把WYCountingLabel
这个类拖到项目中即可,我给WYCountingLabel
扩展了一个formatBlock可以让label根据数字做一些个性化展示,例如加逗号等。和一个wy_countFrom:to:duration:
可以快速给label添加数字动画的方法
github:https://github.com/wangyansnow/WYCountingLabel
例:
- (void)viewDidLoad {
[super viewDidLoad];
self.countingLabel = [[WYCountingLabel alloc] initWithFrame:CGRectMake(20, 80, 100, 24)];
[self.view addSubview:self.countingLabel];
__weak typeof(self) weakSelf = self;
[self.countingLabel setWy_FormatBlock:^NSString *(double wy_number){
return [NSString stringWithFormat:@"%.2f", wy_number];
}];
}
- (IBAction)startCountingBtnClick:(UIButton *)sender {
static double number = 1340;
number += 1457;
self.countingLabel.wy_number = number;
}
- (IBAction)fromBtnClick:(UIButton *)sender {
[self.countingLabel wy_countFrom:0 to:1576 duration:2.0];
}