大刘的 iOS 自学笔记

UITextField文本限制输入

2018-12-05  本文已影响14人  大刘

在项目中UITextField(or UITextView)限制输入的需求普遍存在,在Android的xml UI布局中可以轻松的指定maxLength代表可以最多键入的字符数量,digits代表只允许输入的字符集合,但是在iOS系统中,不得不吐槽的是系统并没有给我们这两个属性去设置,并且键盘遮挡的输入框的事还需要我们自己处理,这确实应当是系统来做的。

我们这次只谈文本输入的限制。

简单的需求:

一个文本输入框只允许输入数字,且长度<=11位

这是一个很简单的需求,但是做起来有些麻烦,我找了很多第三方库经过各种测试后发现都不能很好的解决这个问题,因为要适应多种情况,先来看一些事项:

Code:

-- ViewController.m --
    
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.textField = [[UITextField alloc] initWithFrame:CGRectMake(20, 100, self.view.frame.size.width-40, 40)];
    self.textField.borderStyle = UITextBorderStyleBezel;
    self.textField.delegate = self;
    [self.view addSubview:self.textField];
}

#pragma mark - <UITextFieldDelegate>

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    return [InputingValidator validatePhone:textField shouldChangeCharactersInRange:range replacementString:string];
}



-- InputingValidator.m --
#import "InputingValidator.h"

@implementation InputingValidator

+ (BOOL)validatePhone:(UITextField *)inputField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)rangeString {
    if ([self isNullOrEmpty:rangeString]) {
        return YES;
    }
    else {
        NSString *text = inputField.text;
        NSString *replaceString = [self getNumber:rangeString];
        if ([self isNullOrEmpty:replaceString]) {
            return NO;
        }
        if (replaceString.length + inputField.text.length <= 11 && [replaceString isEqualToString:rangeString]) {
            return YES;
        }
        NSInteger limitLength = MAX(0, 11 - (text.length - range.length));
        if (limitLength <= 0) {
            return NO;
        }
        replaceString = [replaceString substringToIndex:MIN(limitLength, replaceString.length)];
        [self textField:inputField replaceString:replaceString forRange:range];
        return NO;
    }
}

+ (void)textField:(id<UITextInput>)inputField replaceString:(NSString *)replaceString forRange:(NSRange)range {
    UITextPosition *beginning = inputField.beginningOfDocument;
    UITextPosition *start = [inputField positionFromPosition:beginning offset:range.location];
    UITextPosition *end = [inputField positionFromPosition:start offset:range.length];
    UITextRange *textRange = [inputField textRangeFromPosition:start toPosition:end];
    
    // this will be the new cursor location after insert/paste/typing
    NSInteger cursorOffset = [inputField offsetFromPosition:beginning toPosition:start] + replaceString.length;
    
    [inputField replaceRange:textRange withText:replaceString];
    
    // https://stackoverflow.com/questions/11157791/how-to-move-cursor-in-uitextfield-after-setting-its-value
    // setText:或replaceRange:withText:之后马上setCursor位置错乱,Weired.
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        UITextPosition *newCursorPosition = [inputField positionFromPosition:inputField.beginningOfDocument offset:cursorOffset];
        UITextRange *newSelectedRange = [inputField textRangeFromPosition:newCursorPosition toPosition:newCursorPosition];
        [inputField setSelectedTextRange:newSelectedRange];
    });
}

+ (NSString *)getNumber:(NSString *)originStr {
    if (!originStr || originStr.length <= 0 || [originStr isKindOfClass:[NSNull class]]) {
        return nil;
    }
    NSMutableString *replaceStr = [NSMutableString stringWithCapacity:originStr.length];
    for (NSInteger i = 0; i < originStr.length; i++) {
        NSString *subStr = [originStr substringWithRange:NSMakeRange(i, 1)];
        if ([self containsOnlyNumbers:subStr]) {
            [replaceStr appendString:subStr];
        }
    }
    if ([self isNullOrEmpty:replaceStr]) {
        return nil;
    }
    return replaceStr;
}

// 此代码可放在NSString+XXX中,声明为:- (BOOL)isNullOrEmpty;
+ (BOOL)isNullOrEmpty:(NSString *)string {
    if (!string || string.length <= 0 || [string isKindOfClass:[NSNull class]]) {
        return YES;
    }
    return NO;
}

// 此代码可放在NSString+XXX中, 声明为:- (BOOL)containsOnlyNumbers;
+ (BOOL)containsOnlyNumbers:(NSString *)string {
    NSCharacterSet *numbers = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
    return ([string rangeOfCharacterFromSet:numbers].location == NSNotFound);
}

@end
上一篇下一篇

猜你喜欢

热点阅读