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
原创粉丝点击