源码下载地址: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原文:http://blog.csdn.net/iitvip/article/details/41892997