2019-01-03 18:03:44 +08:00
|
|
|
//
|
|
|
|
|
// CRBoxInputView.m
|
|
|
|
|
// CRBoxInputView
|
|
|
|
|
//
|
|
|
|
|
// Created by Chobits on 2019/1/3.
|
|
|
|
|
// Copyright © 2019 Chobits. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#import "CRBoxInputView.h"
|
|
|
|
|
#import "Masonry.h"
|
|
|
|
|
#import "CRBoxInputCell.h"
|
2019-01-03 18:43:31 +08:00
|
|
|
#import "CRBoxTextView.h"
|
2019-01-03 18:03:44 +08:00
|
|
|
|
2019-01-03 19:13:36 +08:00
|
|
|
typedef NS_ENUM(NSInteger, CRBoxTextChangeType) {
|
|
|
|
|
CRBoxTextChangeType_NoChange,
|
|
|
|
|
CRBoxTextChangeType_Insert,
|
|
|
|
|
CRBoxTextChangeType_Delete,
|
|
|
|
|
};
|
|
|
|
|
|
2019-01-03 18:03:44 +08:00
|
|
|
@interface CRBoxInputView () <UITextViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate>
|
|
|
|
|
{
|
2019-01-03 19:13:36 +08:00
|
|
|
NSInteger _oldLength;
|
2019-01-03 18:03:44 +08:00
|
|
|
}
|
|
|
|
|
|
2019-01-03 18:43:31 +08:00
|
|
|
@property (nonatomic, strong) CRBoxTextView *textView;
|
2019-01-03 18:03:44 +08:00
|
|
|
@property (nonatomic, strong) UICollectionView *mainCollectionView;
|
2019-01-03 19:13:36 +08:00
|
|
|
@property (nonatomic, strong) NSMutableArray <NSString *> *valueArr;
|
2019-01-04 15:28:43 +08:00
|
|
|
@property (nonatomic, strong) NSMutableArray <CRBoxInputCellProperty *> *cellPropertyArr;
|
2019-01-03 18:03:44 +08:00
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation CRBoxInputView
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (instancetype)initWithFrame:(CGRect)frame{
|
2019-01-03 18:03:44 +08:00
|
|
|
self = [super initWithFrame:frame];
|
|
|
|
|
if (self) {
|
|
|
|
|
[self initDefaultValue];
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (instancetype)init
|
2019-01-03 18:03:44 +08:00
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (self) {
|
|
|
|
|
[self initDefaultValue];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)initDefaultValue{
|
2019-01-03 19:13:36 +08:00
|
|
|
_oldLength = 0;
|
2019-01-03 19:54:13 +08:00
|
|
|
self.ifNeedSecurity = NO;
|
2019-01-03 19:44:13 +08:00
|
|
|
self.securityDelay = 0.3;
|
2019-01-03 18:03:44 +08:00
|
|
|
self.codeLength = 4;
|
|
|
|
|
self.ifNeedCursor = YES;
|
|
|
|
|
self.backgroundColor = [UIColor clearColor];
|
|
|
|
|
_valueArr = [NSMutableArray new];
|
|
|
|
|
[self beginEdit];
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)loadAndPrepareView
|
|
|
|
|
{
|
2019-01-03 18:03:44 +08:00
|
|
|
if (_codeLength<=0) {
|
|
|
|
|
NSAssert(NO, @"请输入大于0的验证码位数");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
[self generateCellPropertyArr];
|
2019-01-04 15:28:43 +08:00
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
// mainCollectionView
|
2019-01-03 18:03:44 +08:00
|
|
|
[self addSubview:self.mainCollectionView];
|
|
|
|
|
[self.mainCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.edges.mas_equalTo(UIEdgeInsetsZero);
|
|
|
|
|
}];
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
// textView
|
2019-01-03 18:03:44 +08:00
|
|
|
[self addSubview:self.textView];
|
|
|
|
|
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.edges.mas_equalTo(UIEdgeInsetsZero);
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)generateCellPropertyArr
|
2019-01-04 15:28:43 +08:00
|
|
|
{
|
|
|
|
|
[self.cellPropertyArr removeAllObjects];
|
|
|
|
|
for (int i = 0; i < self.codeLength; i++) {
|
|
|
|
|
[self.cellPropertyArr addObject:[self.customCellProperty copy]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.cellPropertyArr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-03 18:03:44 +08:00
|
|
|
#pragma mark - TextViewEdit
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)beginEdit{
|
2019-01-03 18:03:44 +08:00
|
|
|
[self.textView becomeFirstResponder];
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)endEdit{
|
2019-01-03 18:03:44 +08:00
|
|
|
[self.textView resignFirstResponder];
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)clearAll{
|
2019-01-03 19:16:09 +08:00
|
|
|
_oldLength = 0;
|
|
|
|
|
[_valueArr removeAllObjects];
|
2019-01-03 18:03:44 +08:00
|
|
|
self.textView.text = @"";
|
2019-01-03 19:16:09 +08:00
|
|
|
[self.mainCollectionView reloadData];
|
|
|
|
|
[self triggerBlock];
|
2019-01-03 18:03:44 +08:00
|
|
|
[self beginEdit];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - UITextViewDelegate
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)textViewDidChange:(UITextView *)textView{
|
2019-01-03 18:03:44 +08:00
|
|
|
|
|
|
|
|
NSString *verStr = textView.text;
|
|
|
|
|
|
|
|
|
|
//有空格去掉空格
|
|
|
|
|
verStr = [verStr stringByReplacingOccurrencesOfString:@" " withString:@""];
|
|
|
|
|
if (verStr.length >= _codeLength) {
|
|
|
|
|
verStr = [verStr substringToIndex:_codeLength];
|
|
|
|
|
[self endEdit];
|
|
|
|
|
}
|
|
|
|
|
textView.text = verStr;
|
|
|
|
|
|
2019-01-03 19:13:36 +08:00
|
|
|
// 判断删除/增加
|
|
|
|
|
CRBoxTextChangeType boxTextChangeType = CRBoxTextChangeType_NoChange;
|
|
|
|
|
if (verStr.length > _oldLength) {
|
|
|
|
|
boxTextChangeType = CRBoxTextChangeType_Insert;
|
|
|
|
|
}else if (verStr.length < _oldLength){
|
|
|
|
|
boxTextChangeType = CRBoxTextChangeType_Delete;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-03 18:03:44 +08:00
|
|
|
// _valueArr
|
2019-01-03 19:13:36 +08:00
|
|
|
if (boxTextChangeType == CRBoxTextChangeType_Delete) {
|
|
|
|
|
[_valueArr removeLastObject];
|
|
|
|
|
}else if (boxTextChangeType == CRBoxTextChangeType_Insert){
|
|
|
|
|
if (verStr.length > 0) {
|
2019-01-03 19:39:22 +08:00
|
|
|
if (_valueArr.count > 0) {
|
|
|
|
|
[self replaceValueArrToAsteriskWithIndex:_valueArr.count - 1 needEqualToCount:NO];
|
|
|
|
|
}
|
2019-01-03 19:13:36 +08:00
|
|
|
NSString *subStr = [verStr substringWithRange:NSMakeRange(verStr.length - 1, 1)];
|
|
|
|
|
[self->_valueArr addObject:subStr];
|
2019-01-03 19:39:22 +08:00
|
|
|
[self delayAsteriskProcess];
|
2019-01-03 19:13:36 +08:00
|
|
|
}
|
|
|
|
|
}
|
2019-01-03 18:03:44 +08:00
|
|
|
[_mainCollectionView reloadData];
|
|
|
|
|
|
2019-01-03 19:16:09 +08:00
|
|
|
[self triggerBlock];
|
|
|
|
|
_oldLength = verStr.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)triggerBlock
|
|
|
|
|
{
|
2019-01-03 18:03:44 +08:00
|
|
|
if (self.textDidChangeblock) {
|
|
|
|
|
BOOL isFinished = _valueArr.count == _codeLength ? YES : NO;
|
2019-01-03 19:16:09 +08:00
|
|
|
self.textDidChangeblock(_textView.text, isFinished);
|
2019-01-03 18:03:44 +08:00
|
|
|
}
|
2019-01-03 19:13:36 +08:00
|
|
|
}
|
|
|
|
|
|
2019-01-03 19:44:13 +08:00
|
|
|
#pragma mark - Asterisk
|
2019-01-03 19:39:22 +08:00
|
|
|
// 替换*
|
|
|
|
|
- (void)replaceValueArrToAsteriskWithIndex:(NSInteger)index needEqualToCount:(BOOL)needEqualToCount
|
2019-01-03 19:13:36 +08:00
|
|
|
{
|
2019-01-03 19:54:13 +08:00
|
|
|
if (!self.ifNeedSecurity) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-03 19:39:22 +08:00
|
|
|
if (needEqualToCount && index != _valueArr.count - 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
// if (_valueArr.count > index && ![_valueArr[index] isEqualToString:self.securitySymbol]) {
|
|
|
|
|
// [_valueArr replaceObjectAtIndex:index withObject:self.securitySymbol];
|
|
|
|
|
// }
|
2019-01-03 19:39:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 延时替换*
|
|
|
|
|
- (void)delayAsteriskProcess
|
|
|
|
|
{
|
2019-01-03 19:54:13 +08:00
|
|
|
if (!self.ifNeedSecurity) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-03 19:39:22 +08:00
|
|
|
__weak typeof(self) weakSelf = self;
|
2019-01-03 19:44:13 +08:00
|
|
|
[self delayAfter:_securityDelay dealBlock:^{
|
2019-01-03 19:39:22 +08:00
|
|
|
if (self->_valueArr.count > 0) {
|
|
|
|
|
[weakSelf replaceValueArrToAsteriskWithIndex:self->_valueArr.count-1 needEqualToCount:YES];
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
[self->_mainCollectionView reloadData];
|
|
|
|
|
});
|
2019-01-03 19:13:36 +08:00
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - DelayBlock
|
|
|
|
|
- (void)delayAfter:(CGFloat)delayTime dealBlock:(void (^)(void))dealBlock
|
|
|
|
|
{
|
|
|
|
|
dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime *NSEC_PER_SEC));
|
|
|
|
|
dispatch_after(timer, dispatch_get_main_queue(), ^{
|
|
|
|
|
if (dealBlock) {
|
|
|
|
|
dealBlock();
|
|
|
|
|
}
|
|
|
|
|
});
|
2019-01-03 18:03:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - UICollectionViewDataSource
|
2019-01-04 15:46:16 +08:00
|
|
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
2019-01-03 18:03:44 +08:00
|
|
|
{
|
|
|
|
|
return _codeLength;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
2019-01-03 18:03:44 +08:00
|
|
|
{
|
|
|
|
|
CRBoxInputCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CRBoxInputCellID forIndexPath:indexPath];
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
cell.boxInputCellProperty = self.cellPropertyArr[indexPath.row];
|
2019-01-03 18:03:44 +08:00
|
|
|
cell.ifNeedCursor = self.ifNeedCursor;
|
|
|
|
|
|
|
|
|
|
NSUInteger focusIndex = _valueArr.count;
|
|
|
|
|
cell.selected = indexPath.row == focusIndex ? YES : NO;
|
|
|
|
|
if (_valueArr.count > 0 && indexPath.row <= focusIndex - 1) {
|
2019-01-04 15:28:43 +08:00
|
|
|
[cell quickSetOriginValue:_valueArr[indexPath.row]];
|
2019-01-03 18:03:44 +08:00
|
|
|
}else{
|
2019-01-04 15:28:43 +08:00
|
|
|
[cell quickSetOriginValue:@""];
|
2019-01-03 18:03:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cell;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Setter & Getter
|
2019-01-04 15:46:16 +08:00
|
|
|
- (UICollectionView *)mainCollectionView
|
2019-01-03 18:03:44 +08:00
|
|
|
{
|
|
|
|
|
if (!_mainCollectionView) {
|
|
|
|
|
_mainCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.boxFlowLayout];
|
|
|
|
|
_mainCollectionView.showsHorizontalScrollIndicator = NO;
|
|
|
|
|
_mainCollectionView.backgroundColor = [UIColor clearColor];
|
|
|
|
|
_mainCollectionView.delegate = self;
|
|
|
|
|
_mainCollectionView.dataSource = self;
|
|
|
|
|
[_mainCollectionView registerClass:[CRBoxInputCell class] forCellWithReuseIdentifier:CRBoxInputCellID];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _mainCollectionView;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (CRBoxFlowLayout *)boxFlowLayout
|
2019-01-03 18:03:44 +08:00
|
|
|
{
|
|
|
|
|
if (!_boxFlowLayout) {
|
|
|
|
|
_boxFlowLayout = [CRBoxFlowLayout new];
|
|
|
|
|
_boxFlowLayout.itemSize = CGSizeMake(42, 47);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _boxFlowLayout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setCodeLength:(NSInteger)codeLength
|
|
|
|
|
{
|
|
|
|
|
_codeLength = codeLength;
|
|
|
|
|
self.boxFlowLayout.itemNum = codeLength;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)setKeyBoardType:(UIKeyboardType)keyBoardType{
|
2019-01-03 18:03:44 +08:00
|
|
|
_keyBoardType = keyBoardType;
|
|
|
|
|
self.textView.keyboardType = keyBoardType;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (CRBoxTextView *)textView{
|
2019-01-03 18:03:44 +08:00
|
|
|
if (!_textView) {
|
2019-01-03 18:43:31 +08:00
|
|
|
_textView = [CRBoxTextView new];
|
2019-01-03 18:03:44 +08:00
|
|
|
_textView.tintColor = [UIColor clearColor];
|
|
|
|
|
_textView.backgroundColor = [UIColor clearColor];
|
|
|
|
|
_textView.textColor = [UIColor clearColor];
|
|
|
|
|
_textView.delegate = self;
|
|
|
|
|
_textView.keyboardType = UIKeyboardTypeDefault;
|
|
|
|
|
}
|
|
|
|
|
return _textView;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
- (void)quickSetSecuritySymbol:(NSString *)securitySymbol
|
2019-01-03 19:50:45 +08:00
|
|
|
{
|
|
|
|
|
if (securitySymbol.length != 1) {
|
2019-01-04 15:46:16 +08:00
|
|
|
securitySymbol = @"✱";
|
2019-01-03 19:50:45 +08:00
|
|
|
}
|
2019-01-04 15:28:43 +08:00
|
|
|
|
2019-01-04 15:46:16 +08:00
|
|
|
self.customCellProperty.securitySymbol = securitySymbol;
|
2019-01-04 15:28:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (CRBoxInputCellProperty *)customCellProperty
|
|
|
|
|
{
|
|
|
|
|
if (!_customCellProperty) {
|
|
|
|
|
_customCellProperty = [CRBoxInputCellProperty new];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _customCellProperty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSMutableArray <CRBoxInputCellProperty *> *)cellPropertyArr
|
|
|
|
|
{
|
|
|
|
|
if (!_cellPropertyArr) {
|
|
|
|
|
_cellPropertyArr = [NSMutableArray new];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _cellPropertyArr;
|
2019-01-03 19:50:45 +08:00
|
|
|
}
|
|
|
|
|
|
2019-01-03 18:03:44 +08:00
|
|
|
@end
|