iOS开发一行代码系列:一行搞定输入框优化
来源:互联网 发布:定制婴儿知乎 编辑:程序博客网 时间:2024/05/17 03:58
iOS8以前,我们设置键盘为UIKeyboardTypeNumberPad类型的,我们就不太容易输入字母或者其他的。
iOS8以后,由于支持了第三方输入法,就算设置键盘为UIKeyboardTypeNumberPad类型的,我们随便切换下就很容易输入其他字母啦。
为了解决这样的问题,我们对InputHelper进行优化,这样以后我们就不用为这样的小问题浪费时间了。
常见的小问题还有,评论字数的限制,如果超过120字可能会做截取或者弹出提示框;或者不能输入空格;或者只能输入英文。
源码下载地址:inputHelper
代码如下:
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>typedef void(^InputHelperDoneBlock)(id);typedef void(^InputHelperValidationError)(id,NSString*);typedef NS_ENUM(NSInteger, InputHelperDismissType) { InputHelperDismissTypeNone = 0, InputHelperDismissTypeCleanMaskView, InputHelperDismissTypeTapGusture};typedef NS_ENUM(NSInteger, ValidationType) { ValidationTypeNone = 0, //no limit ValidationTypeNoWhiteSpace, //no whitespace character ValidationTypeNumberInt, //int number only ValidationTypePhone, //phone only ValidationTypeAlphabetAndNumber, //alphabet and number};@interface InputHelper : NSObject+ (InputHelper *)sharedInputHelper;- (void)dismissInputHelper;//keyboard- (void)setupInputHelperForView:(UIView *)view withDismissType:(InputHelperDismissType)dismissType;- (void)setupInputHelperForView:(UIView *)view withDismissType:(InputHelperDismissType)dismissType doneBlock:(InputHelperDoneBlock)doneBlock;//validation- (void)setupValidationType:(ValidationType)type forInputField:(UIView *)inputField;- (void)limitTextLength:(NSInteger)length forInputField:(UIView *)inputField;@end@interface NSString (InputHelper)- (NSString *)trimmedString ;@end
#import "InputHelper.h"#import <objc/objc.h>#import <objc/runtime.h>static NSString *kInputHelperTapGusture= @"kInputHelperTapGusture";static NSString *kInputHelperDismissType= @"kInputHelperDismissType";static NSInteger tapTag = 2014;static NSString *kInputHelperRootViewOriginalOriginY = @"kInputHelperRootViewOriginalOriginY";static NSString *kInputHelperRootViewAllInputFieldOriginYDictionary = @"kInputHelperRootViewAllInputFieldOriginYDictionary";static NSString *kInputHelperRootViewSortedInputFieldArray = @"kInputHelperRootViewSortedInputFieldArray";static NSString *kInputHelperDoneBlock = @"kInputHelperDoneBlock";static NSString *kInputHelperValidationType = @"kInputHelperValidationType";static NSString *kInputHelperInputFiedlTextLength = @"kInputHelperInputFiedlTextLength";static NSString *kInputHelperTextLengthLimit = @"kInputHelperTextLengthLimit";static void setAssociatedObjectForKey(UIView *view ,NSString *key,id value){ objc_setAssociatedObject(view, (__bridge const void *)(key), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}static id getAssociatedObjectForKey(UIView *view ,NSString *key) { return objc_getAssociatedObject(view, (__bridge const void *)(key));}#define INT_NUMBER_SET @"^\\d*$"#define PHONE_SET @"^1{1,}\\d*$"#define ALPHABET_NUMBER_SET @"^[0-9A-Za-z@_.\\-]+$"@interface InputHelperTapGusture: UITapGestureRecognizer@property (assign, nonatomic) NSInteger tag;@end@implementation InputHelperTapGusture@end@interface InputHelper ()@property (strong, nonatomic) UIView *cleanMaskView;@property (strong, nonatomic) UIToolbar *toolBarForCleanMaskView;@property (strong, nonatomic) UIToolbar *toolBar;@property (assign, nonatomic) CGSize keyboardSize;@property (assign, nonatomic) CGFloat perMoveDistanceForInputField;@property (assign, nonatomic) CGRect defaultToolBarFrame;@property (assign, nonatomic) CGRect defaultMaskViewFrame;@property (assign, nonatomic) CGRect toolBarFrameInMaskView;//current root view@property (weak, nonatomic) UIView *currentRootView;@end@implementation InputHelper- (UIToolbar *)createInputHelperToolBar{ UIToolbar *toolBar = [[UIToolbar alloc]initWithFrame:_defaultToolBarFrame]; toolBar.barStyle = UIBarStyleBlackTranslucent; UIBarButtonItem *btnPrevious = [[UIBarButtonItem alloc]initWithTitle:@"上一项" style:UIBarButtonItemStyleDone target:self action:@selector(didClickButtonPrevious)]; UIBarButtonItem *btnNext = [[UIBarButtonItem alloc]initWithTitle:@"下一项" style:UIBarButtonItemStyleDone target:self action:@selector(didClickButtonNext)]; UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]; UIBarButtonItem *btnDown = [[UIBarButtonItem alloc]initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(didClickButtonDone)]; [toolBar setItems:[[NSArray alloc]initWithObjects:btnPrevious,btnNext,spaceItem,btnDown, nil]]; return toolBar;}- (void)initilize{ _defaultToolBarFrame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 40); _defaultMaskViewFrame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height); _toolBarFrameInMaskView = CGRectMake(0, [[UIScreen mainScreen] bounds].size.height - 40, [[UIScreen mainScreen] bounds].size.width, 40); _perMoveDistanceForInputField = 40; _keyboardSize = CGSizeMake(320, 256); //tool bar self.toolBar = [self createInputHelperToolBar]; self.toolBarForCleanMaskView = [self createInputHelperToolBar]; _toolBarForCleanMaskView.frame = _toolBarFrameInMaskView; //tap mask view _cleanMaskView = [[UIView alloc]initWithFrame:_defaultMaskViewFrame]; _cleanMaskView.backgroundColor = [UIColor clearColor]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(didClickButtonDone)]; [_cleanMaskView addGestureRecognizer:tap]; [_cleanMaskView addSubview:_toolBarForCleanMaskView]; NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; [notifCenter addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [notifCenter addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; [notifCenter addObserver:self selector:@selector(updateFirstResponder:) name:UITextFieldTextDidBeginEditingNotification object:nil]; [notifCenter addObserver:self selector:@selector(updateFirstResponder:) name:UITextFieldTextDidEndEditingNotification object:nil]; [notifCenter addObserver:self selector:@selector(updateFirstResponder:) name:UITextViewTextDidBeginEditingNotification object:nil]; [notifCenter addObserver:self selector:@selector(updateFirstResponder:) name:UITextViewTextDidEndEditingNotification object:nil]; [notifCenter addObserver:self selector:@selector(updateInputFieldText:) name:UITextFieldTextDidChangeNotification object:nil]; [notifCenter addObserver:self selector:@selector(updateInputFieldText:) name:UITextViewTextDidChangeNotification object:nil]; }- (instancetype)init{ self = [super init]; if (self) { [self initilize]; } return self;}+ (InputHelper *)sharedInputHelper{ static InputHelper *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[InputHelper alloc]init]; }); return instance;}#pragma mark - APIs- (void)setupInputHelperForView:(UIView *)view withDismissType:(InputHelperDismissType)dismissType doneBlock:(InputHelperDoneBlock)doneBlock{ self.currentRootView = view; setAssociatedObjectForKey(view, kInputHelperDismissType, @(dismissType)); NSMutableDictionary *dic= [NSMutableDictionary new]; setAssociatedObjectForKey(view, kInputHelperRootViewAllInputFieldOriginYDictionary, dic); NSMutableArray *array = [NSMutableArray new]; setAssociatedObjectForKey(view, kInputHelperRootViewSortedInputFieldArray, array); objc_setAssociatedObject(view, (__bridge const void *)(kInputHelperDoneBlock), doneBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); [self checkInputFieldInView:view withViewOriginY:view.frame.origin.y]; NSArray *keys = [getAssociatedObjectForKey(view, kInputHelperRootViewAllInputFieldOriginYDictionary) allKeys]; if (keys.count == 0) { return; } NSArray *sortedOriginYArray = [keys sortedArrayUsingComparator:^(id obj1, id obj2){ if ([obj1 compare:obj2] == NSOrderedDescending){ return NSOrderedDescending; } if ([obj1 compare:obj2] == NSOrderedAscending){ return NSOrderedAscending; } return NSOrderedSame; }]; UIView *inputAccessoryView = _toolBar; if (dismissType == InputHelperDismissTypeNone) { _toolBar.frame = _defaultToolBarFrame; } else if (dismissType == InputHelperDismissTypeCleanMaskView){ inputAccessoryView = _cleanMaskView; } else if (dismissType == InputHelperDismissTypeTapGusture){ setAssociatedObjectForKey(view, kInputHelperTapGusture, kInputHelperTapGusture); } for (NSNumber *key in sortedOriginYArray){ UIView *inputField = [getAssociatedObjectForKey(view, kInputHelperRootViewAllInputFieldOriginYDictionary) objectForKey:key]; [getAssociatedObjectForKey(view, kInputHelperRootViewSortedInputFieldArray) addObject:inputField]; if ([inputField isKindOfClass:[UITextField class]]) { ((UITextField *)inputField).inputAccessoryView = inputAccessoryView; } else if([inputField isKindOfClass:[UITextView class]]){ ((UITextView *)inputField).inputAccessoryView = inputAccessoryView; } else if([inputField isKindOfClass:[UISearchBar class]]){ ((UISearchBar *)inputField).inputAccessoryView = inputAccessoryView; } } }- (void)setupInputHelperForView:(UIView *)view withDismissType:(InputHelperDismissType)dismissType{ [self setupInputHelperForView:view withDismissType:dismissType doneBlock:nil];}- (void)dismissInputHelper{ [self didClickButtonDone];}- (void)setupValidationType:(ValidationType)type forInputField:(UIView *)inputField { setAssociatedObjectForKey(inputField, kInputHelperValidationType, @(type)); switch (type) { case ValidationTypeNumberInt: { [self setKeyBoardType:UIKeyboardTypeNumberPad forInputField:inputField]; } break; case ValidationTypePhone: { [self limitTextLength:11 forInputField:inputField]; [self setKeyBoardType:UIKeyboardTypePhonePad forInputField:inputField]; } break; default: { [self setKeyBoardType:UIKeyboardTypeDefault forInputField:inputField]; } break; } }- (void)limitTextLength:(NSInteger)length forInputField:(UIView *)inputField{ setAssociatedObjectForKey(inputField, kInputHelperTextLengthLimit, @(length));}#pragma mark -- (void)updateFirstResponder:(NSNotification *)aNotification { [self updateButtonEnabledStateForInputField:[self getFirstResponder]];}- (void)checkInputFieldInView:(UIView *)view withViewOriginY:(CGFloat)y{ for (UIView *subView in view.subviews){ if (subView.hidden == YES) { continue; } if ([subView isKindOfClass:[UITextField class]] || [subView isKindOfClass:[UITextView class]] || [subView isKindOfClass:[UISearchBar class]]) { NSNumber *key = [NSNumber numberWithFloat: y + subView.frame.origin.y]; NSMutableDictionary *dic = getAssociatedObjectForKey(_currentRootView, kInputHelperRootViewAllInputFieldOriginYDictionary); [dic setObject:subView forKey:key]; } else { [self checkInputFieldInView:subView withViewOriginY:y + subView.frame.origin.y]; } }}- (UIView *)getFirstResponder{ for (UIView *tf in getAssociatedObjectForKey(_currentRootView, kInputHelperRootViewSortedInputFieldArray)) { if ([tf isFirstResponder]) { return tf; } } return nil;}- (void)didClickButtonPrevious{ UIView *firstResponder = [self getFirstResponder]; UIView *previousInputField = firstResponder; NSArray *sortedInputFields = getAssociatedObjectForKey(_currentRootView, kInputHelperRootViewSortedInputFieldArray); if (![firstResponder isEqual:[sortedInputFields firstObject]]) { previousInputField = [sortedInputFields objectAtIndex:[sortedInputFields indexOfObject:firstResponder] - 1]; [previousInputField becomeFirstResponder]; } [self updateButtonEnabledStateForInputField:previousInputField];}- (void)didClickButtonNext{ UIView *firstResponder = [self getFirstResponder]; UIView *nextInputField = firstResponder; NSArray *sortedInputFields = getAssociatedObjectForKey(_currentRootView, kInputHelperRootViewSortedInputFieldArray); if (![firstResponder isEqual:[sortedInputFields lastObject]]) { nextInputField = [sortedInputFields objectAtIndex:[sortedInputFields indexOfObject:firstResponder] + 1]; [nextInputField becomeFirstResponder]; } [self updateButtonEnabledStateForInputField:nextInputField];}- (void)didClickButtonDone{ [[self getFirstResponder] resignFirstResponder]; CGRect frame = _currentRootView.frame; frame.origin.y = [getAssociatedObjectForKey(_currentRootView, kInputHelperRootViewOriginalOriginY) floatValue]; [UIView animateWithDuration:0.3f animations:^{ _currentRootView.frame = frame; }]; InputHelperDoneBlock doneBlock = getAssociatedObjectForKey(self.currentRootView, kInputHelperDoneBlock); if (doneBlock) { //callback what?? doneBlock(nil); }}- (void)updateButtonEnabledStateForInputField:(UIView *)inputField{ if (inputField) { NSInteger dismissType = [getAssociatedObjectForKey(_currentRootView, kInputHelperDismissType) integerValue]; UIToolbar *toolBar = dismissType == InputHelperDismissTypeCleanMaskView ? _toolBarForCleanMaskView : _toolBar; UIBarButtonItem *previousBarItem = (UIBarButtonItem *)[[toolBar items] objectAtIndex:0]; UIBarButtonItem *nextBarItem = (UIBarButtonItem *)[[toolBar items] objectAtIndex:1]; NSArray *sortedInputFields = getAssociatedObjectForKey(_currentRootView, kInputHelperRootViewSortedInputFieldArray); [previousBarItem setEnabled:[inputField isEqual:[sortedInputFields firstObject]] ? NO : YES]; [nextBarItem setEnabled:[inputField isEqual:[sortedInputFields lastObject]] ? NO : YES]; [self animatedMoveRootViewForInputField:inputField]; } }- (void)animatedMoveRootViewForInputField:(UIView *)inputField{ CGPoint windowPoint = [inputField.superview convertPoint:inputField.frame.origin toView:[[UIApplication sharedApplication]keyWindow]]; CGFloat topY = 74.0f; CGFloat buttomY = [[UIScreen mainScreen]applicationFrame].size.height - _keyboardSize.height - 80; CGRect frame = _currentRootView.frame; if (windowPoint.y < topY ) { frame.origin.y += (1 + (int)((topY - windowPoint.y) / _perMoveDistanceForInputField)) * _perMoveDistanceForInputField; if (frame.origin.y > 0) { frame.origin.y = 0; } } else if (windowPoint.y > buttomY) { frame.origin.y -= ((1 + (int)((windowPoint.y - buttomY) / _perMoveDistanceForInputField)) * _perMoveDistanceForInputField); } [UIView animateWithDuration:0.3f animations:^{ _currentRootView.frame = frame; }];}#pragma mark - Notification methods- (void) keyboardWillShow:(NSNotification *) notif{ if (getAssociatedObjectForKey(_currentRootView, kInputHelperRootViewOriginalOriginY) == nil) { setAssociatedObjectForKey(_currentRootView, kInputHelperRootViewOriginalOriginY, @(_currentRootView.frame.origin.y)); } NSString *str = getAssociatedObjectForKey(_currentRootView, kInputHelperTapGusture); BOOL hasAddGusture = NO; for(id gusture in _currentRootView.gestureRecognizers){ if ([gusture isKindOfClass:[InputHelperTapGusture class]] && ((InputHelperTapGusture *)gusture).tag == tapTag) { hasAddGusture = YES; break; } } if ([str isEqualToString:kInputHelperTapGusture] && !hasAddGusture) { InputHelperTapGusture *tap = [[InputHelperTapGusture alloc]initWithTarget:self action:@selector(didClickButtonDone)]; tap.tag = tapTag; [_currentRootView addGestureRecognizer:tap]; } [self updateButtonEnabledStateForInputField:[self getFirstResponder]];}- (void) keyboardWillHide:(NSNotification *) notif{ NSString *str = getAssociatedObjectForKey(_currentRootView, kInputHelperTapGusture); if ([str isEqualToString:kInputHelperTapGusture]) { for(id gusture in _currentRootView.gestureRecognizers){ if ([gusture isKindOfClass:[InputHelperTapGusture class]] && ((InputHelperTapGusture *)gusture).tag == tapTag) { [_currentRootView removeGestureRecognizer:gusture]; break; } } } }- (void)updateInputFieldText:(NSNotification *)notif{ [self checkInputField:notif.object];}#pragma mark - Validation- (void)setKeyBoardType:(UIKeyboardType) keyboardType forInputField:(UIView *)inputField{ if ([inputField isKindOfClass:[UITextField class]]) { ((UITextField *)inputField).keyboardType = keyboardType; } else if([inputField isKindOfClass:[UITextView class]]){ ((UITextView *)inputField).keyboardType = keyboardType; } else if([inputField isKindOfClass:[UISearchBar class]]){ ((UISearchBar *)inputField).keyboardType = keyboardType; }}- (NSString *)getTextForInputField:(UIView *)inputField{ if ([inputField isKindOfClass:[UITextField class]]) { return ((UITextField *)inputField).text; } else if([inputField isKindOfClass:[UITextView class]]){ return ((UITextView *)inputField).text; } else if([inputField isKindOfClass:[UISearchBar class]]){ return ((UISearchBar *)inputField).text; } return @"";}- (void)setText:(NSString *)text forInputField:(UIView *)inputField{ if ([inputField isKindOfClass:[UITextField class]]) { ((UITextField *)inputField).text = text; } else if([inputField isKindOfClass:[UITextView class]]){ ((UITextView *)inputField).text = text; } else if([inputField isKindOfClass:[UISearchBar class]]){ ((UISearchBar *)inputField).text = text; }}- (void)checkText:(NSString *)text forInputField:(UIView *)inputField validation:(NSString *)validation{ NSInteger preLength = [getAssociatedObjectForKey(inputField, kInputHelperInputFiedlTextLength) integerValue]; NSLog(@"current text %@ len %d,prelen %d",text,[text length],preLength); if (![self isTextAvailable:text forValidation:validation]) { [self setText:[text substringToIndex:MAX(MAX(preLength - 1, 0), text.length -1)] forInputField:inputField]; setAssociatedObjectForKey(inputField, kInputHelperInputFiedlTextLength, @(preLength)); } else { setAssociatedObjectForKey(inputField, kInputHelperInputFiedlTextLength, @(text.length)); } }- (void)checkInputField:(UIView *)inputField{ NSInteger type = [getAssociatedObjectForKey(inputField, kInputHelperValidationType) integerValue]; //length limit NSInteger limitLength = [getAssociatedObjectForKey(inputField, kInputHelperTextLengthLimit) integerValue]; if (limitLength) { NSString *text = [self getTextForInputField:inputField]; if (text.length && text.length > limitLength) { [self setText:[text substringToIndex:limitLength]forInputField:inputField]; } } NSString *text = [self getTextForInputField:inputField]; if (text.length) { switch (type) { case ValidationTypeNone: { //do nothing } break; case ValidationTypeNoWhiteSpace: { [self setText:[text trimmedString] forInputField:inputField]; } break; case ValidationTypeNumberInt: { [self checkText:text forInputField:inputField validation:INT_NUMBER_SET]; } break; case ValidationTypeAlphabetAndNumber: { [self checkText:text forInputField:inputField validation:ALPHABET_NUMBER_SET]; } break; case ValidationTypePhone: { [self checkText:text forInputField:inputField validation:PHONE_SET]; } break; default: { } break; } }}- (BOOL)isTextAvailable:(NSString *)text forValidation:(NSString *)validation { NSPredicate *regexPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",validation]; return [regexPredicate evaluateWithObject:text];}@end@implementation NSString (InputHelper)- (NSString *)trimmedString { return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];}@end
源码下载:inputHelper
1 0
- iOS开发一行代码系列:一行搞定输入框优化
- iOS开发一行代码系列:一行搞定输入框
- iOS开发一行代码系列:一行搞定数据库
- 【iOS 1 行代码系列】之 一行代码搞定automaticallyAdjustsScrollViewInsets
- ios-UITextView 输入字数限制,一行代码搞定
- iOS-UITextView 输入字数限制一行代码搞定
- iOS开发-一行代码搞定自动布局
- 一行代码搞定Weex蓝牙开发
- Dialog全屏,一行代码搞定
- SnackbarUtils:一行代码搞定Snackbar
- iOS一行代码搞定UITableView(UITableView结合ReactiveCocoa)(4)
- iOS 3DES加密解密(一行代码搞定)
- iOS-一行代码搞定复杂的UIBarButtonItem创建
- iOS 3DES加密解密(一行代码搞定)
- iOS开发tableView中如何使headView与上边岩向下偏移,一行代码就可以搞定
- 一行代码搞定你的QueryString(转)
- 一行代码搞定ThoughtWorks面试题
- 一行代码轻松搞定 ie兼容
- gradle 编译 sprint boot: spring mvc 使用jsp
- storm优化topology思路
- 黑马程序员-java环境配置path与classpath
- 如何关闭CAD中的*BAK文件?
- Android 系统重启与关机:Java 代码实现(3)
- iOS开发一行代码系列:一行搞定输入框优化
- 4.查找最小的k 个元素
- Android WebView开发问题及优化汇总
- lesson19
- 人,说到底还是要靠自己。
- CAD中如何删除顽固图层?
- linux0.11init进程及shell原理分析
- OC内存管理剖析
- java只有值传递(P123)