今天实现了下全屏倒计时的小demo并且简单的封装了一下,保证了其封装性和扩展性。只需在你的工程中倒入#import "WZBCountdownLabel.h"
,在需要开始倒计时的地方使用[WZBCountdownLabel play];
即可!
先看效果:
其实功能本身很简单,就是动画改变label的文字,然而我觉得封装很重要,我见过一个界面十几个功能,代码几千行,我觉得这样很不好,一来其它人看你代码的时候会晕头转向,找不着东南西北,二来不利于代码的维护和扩展。
而我在项目中往往会把一个界面的功能分为几大类,然后分模块实现这些功能,外部只需要提供几个简单的方法就可以实现,这样能够很大程度上简化代码,几千行的控制器只剩几百行甚至几十行,这样是不是很爽!
有人可能会说,你这倒计时3秒,不符合我的需求,我要5秒怎么办?简单!只需要用这个方法[WZBCountdownLabel playWithNumber:5];
。
有人可能会说,你这还不能满足我的需求,我要在5秒之后显示一个文字,怎么办?简单!只需要用这个方法[WZBCountdownLabel playWithNumber:5 endTitle:@"GO!"];
有人可能会说,你这还不能满足我的需求,我要在5秒文字显示完成之后做一些其它操作,怎么办?简单!我提供了两种方法通知控制器,没错,代理和block。首先签订协议让控制器成为此label的代理,因为一直用的类方法,所以绑定代理同样是提供一个类方法:[WZBCountdownLabel addDelegate:self];
然后实现代理方法即可:
- (void)countdownSuccess:(WZBCountdownLabel *)label {
// do something
}
block是这样用的:
[WZBCountdownLabel setCountdownSuccessBlock:^(WZBCountdownLabel *label) {
// countdown success
}];
有人可能还会说,这样还是不能满足我的需求,我想要在开始动画的时候做些事情。这个监听也是有的:
block
[WZBCountdownLabel addCountdownBeginBlock:^(WZBCountdownLabel *label) {
// countdown begin
}];
delegate
- (void)countdownBegin:(WZBCountdownLabel *)label {
NSLog(@"delegateBegin");
}
需要注意的是:为了顺利执行,block和代理的绑定,必须要放在play方法的前面,不然会监听不到
最后,我提供了一个方法可以一行代码实现以上所有功能,look me:
/*
* return WZBCountdownLabel对象
* number : 倒计时开始的数字
* endTitle : 结束语
* begin : 倒计时开始的回调
* success : 倒计时成功的回调
*/
[WZBCountdownLabel playWithNumber:5 endTitle:@"GO" begin:^(WZBCountdownLabel *label) {
NSLog(@"blockBegin");
} success:^(WZBCountdownLabel *label) {
NSLog(@"blockSuccess");
}];
下面简单讲下我的实现部分
+ (instancetype)play {
return [self playWithNumber:0];
}
+ (instancetype)playWithNumber:(NSInteger)number {
return [self playWithNumber:number endTitle:nil];
}
+ (instancetype)playWithNumber:(NSInteger)number endTitle:(NSString *)endTitle {
return [self playWithNumber:number endTitle:endTitle success:nil];
}
+ (instancetype)playWithNumber:(NSInteger)number success:(CountdownSuccessBlock)success {
return [self playWithNumber:number endTitle:nil success:success];
}
上面这几个方法最终都会走到下边这个方法,核心代码:
+ (instancetype)playWithNumber:(NSInteger)number endTitle:(NSString *)endTitle begin:(CountdownBeginBlock)begin success:(CountdownSuccessBlock)success {
// isAnimationing 用来判断目前是否在动画
if (isAnimationing) return nil;
WZBCountdownLabel *label = [WZBCountdownLabel share];
label.hidden = NO;
// 给全局属性赋值
// 默认三秒
label.number = 3;
if (number && number > 0) label.number = number;
if (endTitle) label.endTitle = endTitle;
if (success) label.countdownSuccessBlock = success;
if (begin) label.countdownBeginBlock = begin;
[self setupLabelBase:label];
// 动画倒计时部分
[self scaleActionWithBeginBlock:begin andSuccessBlock:success label:label];
return label;
}
// 动画倒计时部分
+ (void)scaleActionWithBeginBlock:(CountdownBeginBlock)begin andSuccessBlock:(CountdownSuccessBlock)success label:(WZBCountdownLabel *)label {
if (!isAnimationing) { // 如果不在动画才走开始的代理和block
if (begin) begin(label);
if ([label.delegate respondsToSelector:@selector(countdownBegin:)]) [label.delegate countdownBegin:label];
}
// 这个判断用来表示有没有结束语
if (label.number >= (label.endTitle ? 0 : 1)) {
isAnimationing = YES;
label.text = label.number == 0 ? label.endTitle : [NSString stringWithFormat:@"%zd", label.number];
[UIView animateWithDuration:1 animations:^{
label.transform = CGAffineTransformIdentity;
label.alpha = 1;
} completion:^(BOOL finished) {
if (finished) {
label.number--;
label.alpha = 0;
label.transform = CGAffineTransformScale(label.transform, 10, 10);
[self scaleActionWithBeginBlock:begin andSuccessBlock:success label:label];
}
}];
} else {
// 调用倒计时完成的代理和block
if ([label.delegate respondsToSelector:@selector(countdownSuccess:)]) [label.delegate countdownSuccess:label];
if (success) success(label);
[self hidden];
}
}
本demo中的label并不是加在window上的,因为我发现这样会有问题。就是在动画还未结束的时候,界面跳转了,我想大多需求是需要隐藏这个倒计时的,但如果加在window上label不会隐藏。所以我选择把label加在当前控制器的view上
/// 这个方法是拿到当前正在显示的控制器,不管是push进去的,还是present进去的都能拿到,相信很多项目会用到。拿去不谢!
- (UIViewController *)getVisibleViewControllerFrom:(UIViewController*)vc {
if ([vc isKindOfClass:[UINavigationController class]]) {
return [self getVisibleViewControllerFrom:[((UINavigationController*) vc) visibleViewController]];
}else if ([vc isKindOfClass:[UITabBarController class]]){
return [self getVisibleViewControllerFrom:[((UITabBarController*) vc) selectedViewController]];
} else {
if (vc.presentedViewController) {
return [self getVisibleViewControllerFrom:vc.presentedViewController];
} else {
return vc;
}
}
}
最后, demo在这
如果喜欢我的文章,记得点击喜欢或者关注我哦!
您还可以加入我们的群,大家庭期待您的加入!