一個(gè)簡(jiǎn)單的獲取驗(yàn)證碼控件的封裝

寫(xiě)在前面

在日常的開(kāi)發(fā)過(guò)程中,獲取驗(yàn)證碼是一個(gè)常見(jiàn)的功能。一般情況下,為了提高用戶(hù)體驗(yàn),產(chǎn)品都會(huì)在點(diǎn)擊獲取驗(yàn)證碼之后,讓這個(gè)點(diǎn)擊控件做一個(gè)漸變動(dòng)畫(huà),設(shè)置一個(gè)時(shí)長(zhǎng),然后可以點(diǎn)擊重新獲取。這是一個(gè)非常簡(jiǎn)單且經(jīng)常用到的功能,可以考慮將這個(gè)小控件直接封裝出來(lái),方便隨時(shí)使用。

實(shí)現(xiàn)效果

效果.gif

實(shí)現(xiàn)思路

自定義一個(gè)UIView,在這個(gè)View上添加一個(gè)顯示進(jìn)度的ProgressView,和一個(gè)顯示文字的UILabel。通過(guò)NSTimer修改UILabel上的文字,漸變的動(dòng)畫(huà)就是簡(jiǎn)單的UIView動(dòng)畫(huà),通過(guò)改變ProgressView的frame來(lái)實(shí)現(xiàn)。

實(shí)現(xiàn)代碼

創(chuàng)建一個(gè)XKCaptchaView繼承于UIView,在.h頭文件中聲明需要的屬性和方法。

#import <UIKit/UIKit.h>

@class XKCaptchaView;

// 點(diǎn)擊XKCaptchaView觸發(fā)的回調(diào)Block
typedef void(^XKCaptchaActionBlock)(XKCaptchaView *view);

@interface XKCaptchaView : UIView

// 間隔時(shí)長(zhǎng)(指定一個(gè)時(shí)長(zhǎng),在這個(gè)時(shí)長(zhǎng)之后控件可以重新點(diǎn)擊)
@property (nonatomic, assign) NSTimeInterval reEnableTimeInterval;

// 進(jìn)度視圖的背景顏色
@property (nonatomic, strong) UIColor *progressViewBgColor;

// 初始化方法
- (instancetype)initWithFrame:(CGRect)frame reEnableTimeInterval:(NSTimeInterval)interval actionBlock:(XKCaptchaActionBlock)actionBlock;

// 開(kāi)始動(dòng)畫(huà)
- (void)startAnimation;

// 回到最初的狀態(tài)
- (void)changToNormal;

@end

實(shí)現(xiàn)文件的代碼如下:

#import "XKCaptchaView.h"

@implementation XKCaptchaView {
    
    UIView *_reEnableProgressView;
    
    UILabel *_titleLabel;
    
    XKCaptchaActionBlock _actionBlock;
    
    NSTimer *_timer;
    
    NSInteger _timerInteger;
}

- (void)dealloc {
    
    [_timer invalidate];
    
    _timer = nil;
    
    [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
}

- (instancetype)initWithFrame:(CGRect)frame reEnableTimeInterval:(NSTimeInterval)interval actionBlock:(XKCaptchaActionBlock)actionBlock {
    
    if (self = [super initWithFrame:frame]) {
        
        _reEnableTimeInterval = interval;
        
        _reEnableProgressView = [[UIView alloc] initWithFrame:self.bounds];
        
        self.backgroundColor = [UIColor lightGrayColor];
        
        _reEnableProgressView.backgroundColor = [UIColor orangeColor];
        
        if (actionBlock) {
            _actionBlock = actionBlock;
        }
        
        UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)];
        
        [self addGestureRecognizer:tap];
        
        [self addSubview:_reEnableProgressView];
        
        _titleLabel = [[UILabel alloc] initWithFrame:self.bounds];
        
        _titleLabel.text = @"獲取驗(yàn)證碼";
        
        _titleLabel.textAlignment = NSTextAlignmentCenter;
        
        _titleLabel.textColor = [UIColor whiteColor];
        
        _timerInteger = interval;
        
        [self addSubview:_titleLabel];
    }
    
    return self;
}

- (void)handleTap {
    
    if (_actionBlock) {
     
        _actionBlock(self);
    }
}

- (void)change {
    
    if (_timerInteger == 0) {
        
        [_timer invalidate];
        
        _titleLabel.text = @"獲取驗(yàn)證碼";
        
        _timerInteger = _reEnableTimeInterval;
        
        return;
    }
    
    _timerInteger--;
    
    _titleLabel.text = [NSString stringWithFormat:@"獲取驗(yàn)證碼(%ld)",(long)_timerInteger];
}

- (void)startAnimation {
    
    _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(change) userInfo:nil repeats:YES];
    
    [_timer fire];
    
    self.userInteractionEnabled = NO;
    
    _reEnableProgressView.frame = CGRectMake(0, 0, 0, _reEnableProgressView.frame.size.height);
    
    [UIView animateWithDuration:_reEnableTimeInterval animations:^{
        
        _reEnableProgressView.frame = self.bounds;
        
    } completion:^(BOOL finished) {
        
        self.userInteractionEnabled = YES;
    }];
}

- (void)changToNormal {
    
    [_timer invalidate];
    
    _timerInteger = _reEnableTimeInterval;
    
    [_reEnableProgressView.layer removeAllAnimations];
    
    _titleLabel.text = @"獲取驗(yàn)證碼";
}

- (void)setProgressViewBgColor:(UIColor *)progressViewBgColor {
    
    _progressViewBgColor = progressViewBgColor;
    
    _reEnableProgressView.backgroundColor = progressViewBgColor;
}

@end

平時(shí)寫(xiě)代碼有一個(gè)壞習(xí)慣,就是實(shí)現(xiàn)文件不喜歡寫(xiě)注釋。這里簡(jiǎn)單解釋一下上面的代碼,在初始化方法中向XKCaptchaView添加了reEnableProgressView進(jìn)度View,顯示文字的titleLabel,并且初始化了一些默認(rèn)的配置信息。向XKCaptchaView添加了單擊手勢(shì),用來(lái)接收處理點(diǎn)擊事件。最主要的方法就是- (void)startAnimation這個(gè)方法,在這個(gè)方法中,初始化了定時(shí)器,開(kāi)始動(dòng)畫(huà)之后,XKCaptchaView便不再響應(yīng)用戶(hù)操作,直到動(dòng)畫(huà)完成,或者手動(dòng)調(diào)用- (void)changToNormal方法。設(shè)置reEnableProgressViewframe,然后根據(jù)reEnableTimeInterval改變其寬度。定時(shí)器每秒執(zhí)行一次- (void)change方法,在這個(gè)方法中改變titleLabel上的文字,當(dāng)timerInteger為0時(shí),停止定時(shí)器,還原titleLabel- (void)changToNormal該方法是用來(lái)還原整個(gè)控件的狀態(tài)的,需要手動(dòng)調(diào)用。這個(gè)方法存在的意義是,點(diǎn)擊控件發(fā)起網(wǎng)絡(luò)請(qǐng)求去獲取驗(yàn)證碼,驗(yàn)證碼獲取成功了之后,reEnableProgressView就沒(méi)有繼續(xù)做動(dòng)畫(huà)的必要了。所以這里提供這樣一個(gè)方法。- (void)changToNormal里面也都是簡(jiǎn)單的操作,首先停止定時(shí)器,重新將reEnableTimeInterval賦值給timerInteger,移除reEnableProgressView的動(dòng)畫(huà),還原titleLabel。這里不用將XKCaptchaViewuserInteractionEnabled設(shè)置為YES。因?yàn)樵谝瞥?code>reEnableProgressView動(dòng)畫(huà)的時(shí)候,會(huì)執(zhí)行UIView動(dòng)畫(huà)的completion回調(diào)。最終,我們就實(shí)現(xiàn)了這樣一個(gè)簡(jiǎn)單的需求。

簡(jiǎn)單的使用

在控制器中簡(jiǎn)單使用自定義的XKCaptchaView測(cè)試一下看看是否滿(mǎn)足需求。

#import "ViewController.h"
#import "XKCaptchaView.h"

@interface ViewController ()

@property (nonatomic, strong) XKCaptchaView *captchaView;

@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    [self.view addSubview:self.captchaView];
}

- (XKCaptchaView *)captchaView {
    
    if (!_captchaView) {
        
        _captchaView = [[XKCaptchaView alloc] initWithFrame:CGRectMake(0, 0, 150, 30) reEnableTimeInterval:60 actionBlock:^(XKCaptchaView *view) {
            
            [view startAnimation];
            
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                
                [[[UIAlertView alloc] initWithTitle:@"溫馨提示" message:@"驗(yàn)證碼獲取成功" delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil] show];
                
                [self.captchaView changToNormal];
                
            });
            
        }];
        
        _captchaView.center = self.view.center;
    }
    return _captchaView;
}
@end

最終的效果如圖

最終效果圖.gif

這就是一個(gè)簡(jiǎn)單獲取驗(yàn)證碼控件的封裝,雖然功能簡(jiǎn)單,但是該有的都有。全部的代碼都已經(jīng)貼出來(lái)了。如果你沒(méi)有時(shí)間閱讀源碼而你又需要這個(gè)小控件的話(huà) 傳送門(mén)在這里
如果你在閱讀或者使用的過(guò)程中發(fā)現(xiàn)錯(cuò)誤或者有什么更好的建議,歡迎留言指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,424評(píng)論 25 708
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫(huà)全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,572評(píng)論 6 30
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫(huà)全貌。在這里你可以看...
    F麥子閱讀 5,141評(píng)論 5 13
  • 本文是《90天產(chǎn)品經(jīng)理訓(xùn)練營(yíng)》第4課,沒(méi)有趕上直播,利用課余時(shí)間補(bǔ)上,依然干貨滿(mǎn)滿(mǎn),對(duì)競(jìng)品分析的來(lái)龍去脈,方法作了...
    方唐先生閱讀 4,336評(píng)論 3 37