一个play方法实现全屏炫酷倒计时的小demo

今天实现了下全屏倒计时的小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在这
如果喜欢我的文章,记得点击喜欢或者关注我哦!



文/杂雾无尘(简书作者)
原文链接:http://www.jianshu.com/p/43a6e362f1a3
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值