Files
CRBoxInputView/PodCode/Classes/CRBoxInputView.m
2020-01-20 16:20:36 +08:00

557 lines
15 KiB
Objective-C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// CRBoxInputView.m
// CRBoxInputView
//
// Created by Chobits on 2019/1/3.
// Copyright © 2019 Chobits. All rights reserved.
//
#import "CRBoxInputView.h"
#import <Masonry/Masonry.h>
#import "CRBoxTextView.h"
typedef NS_ENUM(NSInteger, CRBoxTextChangeType) {
CRBoxTextChangeType_NoChange,
CRBoxTextChangeType_Insert,
CRBoxTextChangeType_Delete,
};
@interface CRBoxInputView () <UICollectionViewDataSource, UICollectionViewDelegate, UITextFieldDelegate>
{
NSInteger _oldLength;
BOOL _ifNeedBeginEdit;
}
@property (nonatomic, strong) UITapGestureRecognizer *tapGR;
@property (nonatomic, strong) CRBoxTextView *textView;
@property (nonatomic, strong) UICollectionView *mainCollectionView;
@property (nonatomic, strong) NSMutableArray <NSString *> *valueArr;
@property (nonatomic, strong) NSMutableArray <CRBoxInputCellProperty *> *cellPropertyArr;
@end
@implementation CRBoxInputView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self initDefaultValue];
[self addNotificationObserver];
}
return self;
}
- (instancetype)init
{
self = [super init];
if (self) {
[self initDefaultValue];
[self addNotificationObserver];
}
return self;
}
- (void)dealloc
{
[self removeNotificationObserver];
}
#pragma mark - Notification Observer
- (void)addNotificationObserver
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
}
- (void)removeNotificationObserver {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)applicationWillResignActive:(NSNotification *)notification
{
// 触发home按下光标动画移除
}
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
// 重新进来后响应,光标动画重新开始
[_mainCollectionView reloadData];
}
#pragma mark - You can inherit
- (void)initDefaultValue
{
_oldLength = 0;
self.ifNeedSecurity = NO;
self.securityDelay = 0.3;
self.codeLength = 4;
self.ifNeedCursor = YES;
self.keyBoardType = UIKeyboardTypeNumberPad;
self.backgroundColor = [UIColor clearColor];
_valueArr = [NSMutableArray new];
_ifNeedBeginEdit = NO;
}
#pragma mark - LoadAndPrepareView
- (void)loadAndPrepareView
{
[self loadAndPrepareViewWithBeginEdit:YES];
}
- (void)loadAndPrepareViewWithBeginEdit:(BOOL)beginEdit
{
if (_codeLength<=0) {
NSAssert(NO, @"请输入大于0的验证码位数");
return;
}
[self generateCellPropertyArr];
// mainCollectionView
[self addSubview:self.mainCollectionView];
[self.mainCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsZero);
}];
// textView
[self addSubview:self.textView];
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.edges.mas_equalTo(UIEdgeInsetsZero);
make.width.height.mas_equalTo(0);
make.left.top.mas_equalTo(0);
}];
// tap
if (self.tapGR.view != self) {
[self addGestureRecognizer:self.tapGR];
}
if (![self.textView.text isEqualToString:self.customCellProperty.originValue]) {
self.textView.text = self.customCellProperty.originValue;
[self textDidChange:self.textView];
}
if (beginEdit) {
[self beginEdit];
}
}
- (void)generateCellPropertyArr
{
[self.cellPropertyArr removeAllObjects];
for (int i = 0; i < self.codeLength; i++) {
[self.cellPropertyArr addObject:[self.customCellProperty copy]];
}
}
#pragma mark - Reload Input View
- (void)reloadInputString:(NSString *_Nullable)value
{
if (![self.textView.text isEqualToString:value]) {
self.textView.text = value;
[self baseTextDidChange:self.textView manualInvoke:YES];
}
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
_ifNeedBeginEdit = YES;
if (self.textEditStatusChangeblock) {
self.textEditStatusChangeblock(CRTextEditStatus_BeginEdit);
}
[self.mainCollectionView reloadData];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
_ifNeedBeginEdit = NO;
if (self.textEditStatusChangeblock) {
self.textEditStatusChangeblock(CRTextEditStatus_EndEdit);
}
[self.mainCollectionView reloadData];
}
#pragma mark - TextViewEdit
- (void)beginEdit{
if (![self.textView isFirstResponder]) {
[self.textView becomeFirstResponder];
}
}
- (void)endEdit{
if ([self.textView isFirstResponder]) {
[self.textView resignFirstResponder];
}
}
- (void)clearAll
{
[self clearAllWithBeginEdit:YES];
}
- (void)clearAllWithBeginEdit:(BOOL)beginEdit
{
_oldLength = 0;
[_valueArr removeAllObjects];
self.textView.text = @"";
[self allSecurityClose];
[self.mainCollectionView reloadData];
[self triggerBlock];
if (beginEdit) {
[self beginEdit];
}
}
#pragma mark - UITextFieldDidChange
- (void)textDidChange:(UITextField *)textField {
[self baseTextDidChange:textField manualInvoke:NO];
}
/**
* textDidChange基操作
* manualInvoke是否为手动调用
*/
- (void)baseTextDidChange:(UITextField *)textField manualInvoke:(BOOL)manualInvoke {
__weak typeof(self) weakSelf = self;
NSString *verStr = textField.text;
//有空格去掉空格
verStr = [verStr stringByReplacingOccurrencesOfString:@" " withString:@""];
if (verStr.length >= _codeLength) {
verStr = [verStr substringToIndex:_codeLength];
[self endEdit];
}
textField.text = verStr;
// 判断删除/增加
CRBoxTextChangeType boxTextChangeType = CRBoxTextChangeType_NoChange;
if (verStr.length > _oldLength) {
boxTextChangeType = CRBoxTextChangeType_Insert;
}else if (verStr.length < _oldLength){
boxTextChangeType = CRBoxTextChangeType_Delete;
}
// _valueArr
if (boxTextChangeType == CRBoxTextChangeType_Delete) {
[self setSecurityShow:NO index:_valueArr.count-1];
[_valueArr removeLastObject];
}else if (boxTextChangeType == CRBoxTextChangeType_Insert){
if (verStr.length > 0) {
if (_valueArr.count > 0) {
[self replaceValueArrToAsteriskWithIndex:_valueArr.count - 1 needEqualToCount:NO];
}
// NSString *subStr = [verStr substringWithRange:NSMakeRange(verStr.length - 1, 1)];
// [strongSelf.valueArr addObject:subStr];
[_valueArr removeAllObjects];
[verStr enumerateSubstringsInRange:NSMakeRange(0, verStr.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf.valueArr addObject:substring];
}];
if (self.ifNeedSecurity) {
if (manualInvoke) {
// 处理所有秘文
[self delaySecurityProcessAll];
}else {
// 只处理最后一个秘文
[self delaySecurityProcessLastOne];
}
}
}
}
[_mainCollectionView reloadData];
_oldLength = verStr.length;
if (boxTextChangeType != CRBoxTextChangeType_NoChange) {
[self triggerBlock];
}
}
#pragma mark - Control security show
- (void)setSecurityShow:(BOOL)isShow index:(NSInteger)index
{
if (index < 0) {
NSAssert(NO, @"index必须大于等于0");
return;
}
CRBoxInputCellProperty *cellProperty = self.cellPropertyArr[index];
cellProperty.ifShowSecurity = isShow;
}
- (void)allSecurityClose
{
[self.cellPropertyArr enumerateObjectsUsingBlock:^(CRBoxInputCellProperty * _Nonnull cellProperty, NSUInteger idx, BOOL * _Nonnull stop) {
if (cellProperty.ifShowSecurity == YES) {
cellProperty.ifShowSecurity = NO;
}
}];
}
- (void)allSecurityOpen
{
[self.cellPropertyArr enumerateObjectsUsingBlock:^(CRBoxInputCellProperty * _Nonnull cellProperty, NSUInteger idx, BOOL * _Nonnull stop) {
if (cellProperty.ifShowSecurity == NO) {
cellProperty.ifShowSecurity = YES;
}
}];
}
#pragma mark - Trigger block
- (void)triggerBlock
{
if (self.textDidChangeblock) {
BOOL isFinished = _valueArr.count == _codeLength ? YES : NO;
self.textDidChangeblock(_textView.text, isFinished);
}
}
#pragma mark - Asterisk 替换密文
/**
* 替换密文
* needEqualToCount是否只替换最后一个
*/
- (void)replaceValueArrToAsteriskWithIndex:(NSInteger)index needEqualToCount:(BOOL)needEqualToCount
{
if (!self.ifNeedSecurity) {
return;
}
if (needEqualToCount && index != _valueArr.count - 1) {
return;
}
[self setSecurityShow:YES index:index];
}
#pragma mark 延时替换最后一个密文
- (void)delaySecurityProcessLastOne
{
__weak __typeof(self)weakSelf = self;
[self delayAfter:self.securityDelay dealBlock:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf.valueArr.count > 0) {
[strongSelf replaceValueArrToAsteriskWithIndex:strongSelf.valueArr.count-1 needEqualToCount:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[strongSelf.mainCollectionView reloadData];
});
}
}];
}
#pragma mark 延时替换所有一个密文
- (void)delaySecurityProcessAll
{
__weak __typeof(self)weakSelf = self;
[self.valueArr enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf replaceValueArrToAsteriskWithIndex:idx needEqualToCount:NO];
}];
[self.mainCollectionView reloadData];
}
#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();
}
});
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _codeLength;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
id tempCell = [self customCollectionView:collectionView cellForItemAtIndexPath:indexPath];
if ([tempCell isKindOfClass:[CRBoxInputCell class]]) {
CRBoxInputCell *cell = (CRBoxInputCell *)tempCell;
cell.ifNeedCursor = self.ifNeedCursor;
// CellProperty
CRBoxInputCellProperty *cellProperty = self.cellPropertyArr[indexPath.row];
cellProperty.index = indexPath.row;
NSString *currentPlaceholderStr = nil;
if (_placeholderText.length > indexPath.row) {
currentPlaceholderStr = [_placeholderText substringWithRange:NSMakeRange(indexPath.row, 1)];
cellProperty.cellPlaceholderText = currentPlaceholderStr;
}
// setOriginValue
NSUInteger focusIndex = _valueArr.count;
if (_valueArr.count > 0 && indexPath.row <= focusIndex - 1) {
[cellProperty setMyOriginValue:_valueArr[indexPath.row]];
}else{
[cellProperty setMyOriginValue:@""];
}
cell.boxInputCellProperty = cellProperty;
if (_ifNeedBeginEdit) {
cell.selected = indexPath.row == focusIndex ? YES : NO;
}else{
cell.selected = NO;
}
}
return tempCell;
}
#pragma mark - Qiuck set
- (void)quickSetSecuritySymbol:(NSString *)securitySymbol
{
if (securitySymbol.length != 1) {
securitySymbol = @"";
}
self.customCellProperty.securitySymbol = securitySymbol;
}
#pragma mark - You can rewrite
- (UICollectionViewCell *)customCollectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CRBoxInputCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CRBoxInputCellID forIndexPath:indexPath];
return cell;
}
#pragma mark - Setter & Getter
- (UITapGestureRecognizer *)tapGR
{
if (!_tapGR) {
_tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(beginEdit)];
}
return _tapGR;
}
- (UICollectionView *)mainCollectionView
{
if (!_mainCollectionView) {
_mainCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.boxFlowLayout];
_mainCollectionView.showsHorizontalScrollIndicator = NO;
_mainCollectionView.backgroundColor = [UIColor clearColor];
_mainCollectionView.delegate = self;
_mainCollectionView.dataSource = self;
_mainCollectionView.layer.masksToBounds = NO;
_mainCollectionView.clipsToBounds = NO;
[_mainCollectionView registerClass:[CRBoxInputCell class] forCellWithReuseIdentifier:CRBoxInputCellID];
}
return _mainCollectionView;
}
- (CRBoxFlowLayout *)boxFlowLayout
{
if (!_boxFlowLayout) {
_boxFlowLayout = [CRBoxFlowLayout new];
_boxFlowLayout.itemSize = CGSizeMake(42, 47);
}
return _boxFlowLayout;
}
- (void)setCodeLength:(NSInteger)codeLength
{
_codeLength = codeLength;
self.boxFlowLayout.itemNum = codeLength;
}
- (void)setKeyBoardType:(UIKeyboardType)keyBoardType{
_keyBoardType = keyBoardType;
self.textView.keyboardType = keyBoardType;
}
- (CRBoxTextView *)textView{
if (!_textView) {
_textView = [CRBoxTextView new];
// _textView.alpha = 0.1;
// _textView.tintColor = [UIColor clearColor];
// _textView.backgroundColor = [UIColor clearColor];
// _textView.textColor = [UIColor clearColor];
_textView.delegate = self;
[_textView addTarget:self action:@selector(textDidChange:) forControlEvents:UIControlEventEditingChanged];
}
return _textView;
}
- (void)setTextContentType:(UITextContentType)textContentType
{
_textContentType = textContentType;
_textView.textContentType = textContentType;
}
- (CRBoxInputCellProperty *)customCellProperty
{
if (!_customCellProperty) {
_customCellProperty = [CRBoxInputCellProperty new];
}
return _customCellProperty;
}
- (NSMutableArray <CRBoxInputCellProperty *> *)cellPropertyArr
{
if (!_cellPropertyArr) {
_cellPropertyArr = [NSMutableArray new];
}
return _cellPropertyArr;
}
- (NSString *)textValue
{
return _textView.text;
}
@synthesize inputAccessoryView = _inputAccessoryView;
- (void)setInputAccessoryView:(UIView *)inputAccessoryView
{
_inputAccessoryView = inputAccessoryView;
self.textView.inputAccessoryView = _inputAccessoryView;
}
- (UIView *)inputAccessoryView
{
return _inputAccessoryView;
}
- (void)setIfNeedSecurity:(BOOL)ifNeedSecurity
{
_ifNeedSecurity = ifNeedSecurity;
if (ifNeedSecurity == YES) {
[self allSecurityOpen];
}else{
[self allSecurityClose];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.mainCollectionView reloadData];
});
}
@end