今天實(shí)現(xiàn)了下全屏倒計(jì)時(shí)的小demo并且簡單的封裝了一下,保證了其封裝性和擴(kuò)展性。只需在你的工程中倒入#import "WZBCountdownLabel.h",在需要開始倒計(jì)時(shí)的地方使用[WZBCountdownLabel play];即可!
先看效果:

其實(shí)功能本身很簡單,就是動(dòng)畫改變label的文字,然而我覺得封裝很重要,我見過一個(gè)界面十幾個(gè)功能,代碼幾千行,我覺得這樣很不好,一來其它人看你代碼的時(shí)候會(huì)暈頭轉(zhuǎn)向,找不著東南西北,二來不利于代碼的維護(hù)和擴(kuò)展。
而我在項(xiàng)目中往往會(huì)把一個(gè)界面的功能分為幾大類,然后分模塊實(shí)現(xiàn)這些功能,外部只需要提供幾個(gè)簡單的方法就可以實(shí)現(xiàn),這樣能夠很大程度上簡化代碼,幾千行的控制器只剩幾百行甚至幾十行,這樣是不是很爽!
有人可能會(huì)說,你這倒計(jì)時(shí)3秒,不符合我的需求,我要5秒怎么辦?簡單!只需要用這個(gè)方法[WZBCountdownLabel playWithNumber:5];。
有人可能會(huì)說,你這還不能滿足我的需求,我要在5秒之后顯示一個(gè)文字,怎么辦?簡單!只需要用這個(gè)方法[WZBCountdownLabel playWithNumber:5 endTitle:@"GO!"];
有人可能會(huì)說,你這還不能滿足我的需求,我要在5秒文字顯示完成之后做一些其它操作,怎么辦?簡單!我提供了兩種方法通知控制器,沒錯(cuò),代理和block。首先簽訂協(xié)議讓控制器成為此label的代理,因?yàn)橐恢庇玫念惙椒?,所以綁定代理同樣是提供一個(gè)類方法:[WZBCountdownLabel addDelegate:self];然后實(shí)現(xiàn)代理方法即可:
- (void)countdownSuccess:(WZBCountdownLabel *)label {
// do something
}
block是這樣用的:
[WZBCountdownLabel setCountdownSuccessBlock:^(WZBCountdownLabel *label) {
// countdown success
}];
有人可能還會(huì)說,這樣還是不能滿足我的需求,我想要在開始動(dòng)畫的時(shí)候做些事情。這個(gè)監(jiān)聽也是有的:
block
[WZBCountdownLabel addCountdownBeginBlock:^(WZBCountdownLabel *label) {
// countdown begin
}];
delegate
- (void)countdownBegin:(WZBCountdownLabel *)label {
NSLog(@"delegateBegin");
}
需要注意的是:為了順利執(zhí)行,block和代理的綁定,必須要放在play方法的前面,不然會(huì)監(jiān)聽不到
最后,我提供了一個(gè)方法可以一行代碼實(shí)現(xiàn)以上所有功能,look me:
/*
* return WZBCountdownLabel對(duì)象
* number : 倒計(jì)時(shí)開始的數(shù)字
* endTitle : 結(jié)束語
* begin : 倒計(jì)時(shí)開始的回調(diào)
* success : 倒計(jì)時(shí)成功的回調(diào)
*/
[WZBCountdownLabel playWithNumber:5 endTitle:@"GO" begin:^(WZBCountdownLabel *label) {
NSLog(@"blockBegin");
} success:^(WZBCountdownLabel *label) {
NSLog(@"blockSuccess");
}];
下面簡單講下我的實(shí)現(xiàn)部分
+ (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];
}
上面這幾個(gè)方法最終都會(huì)走到下邊這個(gè)方法,核心代碼:
+ (instancetype)playWithNumber:(NSInteger)number endTitle:(NSString *)endTitle begin:(CountdownBeginBlock)begin success:(CountdownSuccessBlock)success {
// isAnimationing 用來判斷目前是否在動(dòng)畫
if (isAnimationing) return nil;
WZBCountdownLabel *label = [WZBCountdownLabel share];
label.hidden = NO;
// 給全局屬性賦值
// 默認(rèn)三秒
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];
// 動(dòng)畫倒計(jì)時(shí)部分
[self scaleActionWithBeginBlock:begin andSuccessBlock:success label:label];
return label;
}
// 動(dòng)畫倒計(jì)時(shí)部分
+ (void)scaleActionWithBeginBlock:(CountdownBeginBlock)begin andSuccessBlock:(CountdownSuccessBlock)success label:(WZBCountdownLabel *)label {
if (!isAnimationing) { // 如果不在動(dòng)畫才走開始的代理和block
if (begin) begin(label);
if ([label.delegate respondsToSelector:@selector(countdownBegin:)]) [label.delegate countdownBegin:label];
}
// 這個(gè)判斷用來表示有沒有結(jié)束語
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 {
// 調(diào)用倒計(jì)時(shí)完成的代理和block
if ([label.delegate respondsToSelector:@selector(countdownSuccess:)]) [label.delegate countdownSuccess:label];
if (success) success(label);
[self hidden];
}
}
本demo中的label并不是加在window上的,因?yàn)槲野l(fā)現(xiàn)這樣會(huì)有問題。就是在動(dòng)畫還未結(jié)束的時(shí)候,界面跳轉(zhuǎn)了,我想大多需求是需要隱藏這個(gè)倒計(jì)時(shí)的,但如果加在window上label不會(huì)隱藏。所以我選擇把label加在當(dāng)前控制器的view上
/// 這個(gè)方法是拿到當(dāng)前正在顯示的控制器,不管是push進(jìn)去的,還是present進(jìn)去的都能拿到,相信很多項(xiàng)目會(huì)用到。拿去不謝!
- (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在這
如果喜歡我的文章,記得點(diǎn)擊喜歡或者關(guān)注我哦!
您還可以加入我們的群,大家庭期待您的加入!