来了新公司,马上四个月了。前后参与了两款APP的开发。其中涉及到输入手机号获取验证码的页面,做了三个。第一次的时候,那个APP只有一个地方需要获取验证码,所以代码没有封装。没想到,年后做的另外一款APP,有两个界面,一个是刚刚年后来了做了,一个是在上周,项目打包的前几天。三次做这个都没有封装,每次都需去拷贝原来的代码,然后修改。今天就把这部分给简单地封装了一下。下面是效果图:(只有:获取验证码 那个绿色区域是控件)
控件流程:
1.进入这个页面的时候,获取验证码按钮是灰色 不可点击的
2.手机号输入框中,输入长度位11位时,获取验证码按钮可以的点击,变成绿色的。
3.点击“获取验证码”按钮之后,按钮显示倒计时且不可以点击。
4.倒计时结束和页面下消失的时候,按钮回复初始状态,销毁定时器。
这个基本就是获取验证码处理的基本流程吧。
关于输入框长度的问题,前面有写过:《【iOS】UITextField限制输入长度》。这里不再粘贴代码了。
控件的基本组成:
一种是使用一个UIButton控件,但是这种存在一个问题,就是在倒计时的时候,看起来倒计时文字是每隔一秒闪动一次,用户体验不好。
还有一种就是一个UIlabel+UIImageView,两个控件组成的。UILabel显示文字,UIImageView显示背景颜色。我都是采取的这样一种做法。
控件的制作:
1.做UI
这部分主要注意的是控件的叠加顺序和点击手势是加在哪个控件上面的。
//
// ValidateCodeView.m
// ValidateCodeView
//
// Created by zhuming on 16/3/11.
// Copyright © 2016年 zhuming. All rights reserved.
//
#import "ValidateCodeView.h"
#define orImage1 [UIImage imageNamed:@"icon_yzmsj"] // 可点击的图片
#define orImage2 [UIImage imageNamed:@"icon_program_bg-shenhe"] // 不可点击的图片
// 图片拉伸
#define IMAGE1 [orImage1 stretchableImageWithLeftCapWidth:orImage1.size.width/2 topCapHeight:orImage1.size.height/2]
#define IMAGE2 [orImage2 stretchableImageWithLeftCapWidth:orImage2.size.width/2 topCapHeight:orImage2.size.height/2]
@interface ValidateCodeView ()
/**
* 倒计时 定时器
*/
@property (nonatomic,strong)NSTimer *timer;
/**
* 颜色图片
*/
@property (nonatomic,strong)UIImageView *imageView;
/**
* 倒计时显示label
*/
@property (nonatomic,strong)UILabel *timeLabel;
/**
* 倒计时长度
*/
@property (nonatomic,assign)NSInteger timeCount;
/**
* 备份 倒计时长度
*/
@property (nonatomic,assign)NSInteger timeCount2;
@end
/**
* 初始化视图
*/
- (void)initView:(CGRect)frame{
self.frame = frame;
self.imageView = [[UIImageView alloc] init];
self.imageView.frame = frame;
[self addSubview:self.imageView];
self.timeLabel = [[UILabel alloc] init];
self.timeLabel.frame = frame;
self.timeLabel.textAlignment = NSTextAlignmentCenter;
self.timeLabel.font = [UIFont systemFontOfSize:15];
self.timeLabel.backgroundColor = [UIColor clearColor];
[self addSubview:self.timeLabel];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(getValidateCode)];
[self.timeLabel addGestureRecognizer:tap];
}
/**
* 初始化视图
*
* @param frame frame
* @param timerCount 倒计时长度
*
* @return 视图
*/
- (instancetype)initWithFrame:(CGRect)frame timerCount:(NSInteger)timerCount{
self = [super initWithFrame:frame];
if (self) {
self.timeCount = timerCount;
self.timeCount2 = timerCount;
[self initView:frame];
}
return self;
}
有了上面的方法,创建控件的时候,控件就可以显示出来了。
但是,难点是处理逻辑。其实知道了上面的流程后,处理逻辑也不难了。
2.处理逻辑
/**
* 获取 验证码
*/
- (void)getValidateCode{
[self start];
}
/**
* 开始倒计时
*/
- (void)start{
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];
if ([_delegate respondsToSelector:@selector(startTimeCount)]) {
[_delegate startTimeCount];
}
}
/**
* 倒计时60s
*
* @param timers
*/
-(void)timerFireMethod:(NSTimer*)timers {
self.timeCount -- ;
[self canGetYzm:NO];
self.timeLabel.text = [NSString stringWithFormat:@"重新获取(%0.0ld)",(long)self.timeCount];
if (self.timeCount == 0) {
[self reset];
}
}
/**
* 获取验证码按钮是否可以点击
*
* @param isCan YES: 可以点击 NO:不可以点击
*/
- (void)canGetYzm:(BOOL)isCan{
if (isCan) {
// 按钮可以点击
self.imageView.image = IMAGE1;
self.imageView.userInteractionEnabled = YES;
self.timeLabel.userInteractionEnabled = YES;
self.timeLabel.text = @"获取验证码";
}
else{
// 按钮不可以点击
self.imageView.image = IMAGE2;
self.imageView.userInteractionEnabled = NO;
self.timeLabel.userInteractionEnabled = NO;
}
}
/**
* 还原验证控件
*/
-(void)reset{
[self canGetYzm:NO];
self.timeCount = self.timeCount2;
self.timeLabel.text = @"获取验证码";
[self.timer invalidate];
self.timer = nil;
if ([_delegate respondsToSelector:@selector(endTimeCount)]) {
[_delegate endTimeCount];
}
}
逻辑无非就是,按钮点击的时候,开始的倒计时,倒计时结束或是视图消失的时候结束倒计时更改视图控件状态。
但是我们如果使用这个控件,就需要知道控件点击开始倒计时和倒计时结束或是视图消失的时候结束倒计时这两类状态或是动作。
这样,我们就需要使用代理把这些传出来。
看看控件的.h文件
//
// validateCodeView.h
// ValidateCodeView
//
// Created by zhuming on 16/3/11.
// Copyright © 2016年 zhuming. All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol ValidateCodeDelegate <NSObject>
@optional
/**
* 点击后开始倒计时
*/
- (void)startTimeCount;
/**
* 倒计时结束
*/
- (void)endTimeCount;
@end
@interface ValidateCodeView : UIView
/**
* 代理
*/
@property (nonatomic,weak)id<ValidateCodeDelegate>delegate;
/**
* 初始化视图
*
* @param frame frame
* @param timerCount 倒计时长度
*
* @return 视图
*/
- (instancetype)initWithFrame:(CGRect)frame timerCount:(NSInteger)timerCount;
/**
* 获取验证码按钮是否可以点击
*
* @param isCan YES: 可以点击 NO:不可以点击
*/
- (void)canGetYzm:(BOOL)isCan;
/**
* 还原验证码控件
* 控制器消失的时候 需要调用这个方法
*/
-(void)reset;
@end
控件的使用
//
// ViewController.m
// ValidateCodeView
//
// Created by zhuming on 16/3/11.
// Copyright © 2016年 zhuming. All rights reserved.
//
#import "ViewController.h"
#import "SecondViewController.h"
#import "ValidateCodeView.h"
@interface ViewController ()<ValidateCodeDelegate>
@property (weak, nonatomic) IBOutlet UIView *validateCode;
/**
* 验证码控件
*/
@property (nonatomic,strong)ValidateCodeView *vaView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化 验证码控件
self.vaView = [[ValidateCodeView alloc] initWithFrame:CGRectMake(0, 0, self.validateCode.frame.size.width, self.validateCode.frame.size.height) timerCount:10];
[self.vaView canGetYzm:YES]; // 控件可以点击
self.vaView.delegate = self; // 关联代理
[self.validateCode addSubview:self.vaView];
// Do any additional setup after loading the view, typically from a nib.
}
/**
* 开始倒计时
*/
- (void)startTimeCount{
NSLog(@"开始倒计时");
}
/**
* 倒计时结束
*/
- (void)endTimeCount{
NSLog(@"结束倒计时");
[self.vaView canGetYzm:YES];
}
/**
* 跳转到下一界面
*
* @param sender sender description
*/
- (IBAction)nextBtnClick:(UIButton *)sender {
SecondViewController *sVc = [[SecondViewController alloc] init];
[self presentViewController:sVc animated:YES completion:nil];
}
/**
* 视图将要消失
*
* @param animated animated description
*/
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.vaView reset];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
在第二个页面只做了一件事,延时3秒后返回。
为什么要控件复位
为什么需要在视图消失的时候,把控件复位?
如果不复位的时候,当倒计时进行中的时候发生了页面的跳转,当再次返回验证码页面的时候,倒计时还在继续。(前提,所有动作都在验证码倒计时时间内完成)。
//
// SecondViewController.m
// ValidateCodeView
//
// Created by zhuming on 16/3/11.
// Copyright © 2016年 zhuming. All rights reserved.
//
#import "SecondViewController.h"
@interface SecondViewController ()
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
// 延时 3S 后返回
[self performSelector:@selector(back) withObject:nil afterDelay:3];
// Do any additional setup after loading the view.
}
- (void)back{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
动画效果图
控件github代码地址:请点击我。