美文网首页
iOS--UITextFiled输入限制的摸索

iOS--UITextFiled输入限制的摸索

作者: 乐逍遥的笔记 | 来源:发表于2020-04-30 11:03 被阅读0次

最近因为项目的需要,需要很多输入框输入填写信息,像手机号必须输入数字,并且长度不能超过11位,像输入收货地址虽然没有格式的限制,但是最好也不要太长了,一般限制100到50个字符就行了。本文的目的是讨论出一个优雅的解决输入框限制的一种方式,力求简洁高效又将代码量降至最低。

目录:

1.最容易想到的解决方案。
2.笔者的解决方法。

一、我们容易想到的方法:

在正常的开发中,不可避免的会出现输入手机号码的情况,那么输入手机号码的时候就必须限制只能接受数字、长度必须不能大于11位。那么我们经常用到的是UITextFieldDelegate中的代理方法:- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
笔者以输入手机号的输入框为例子:
第一步:我们先定义输入规则和输入长度

static NSString *inputNumber = @"0123456789";
static int phonelength = 11;

第二步:我们创建好一个UITextField的变量,并遵循UITextFieldDelegate

CGFloat width = self.view.frame.size.width-20;
    UITextField *inputField = [[UITextField alloc] initWithFrame:CGRectMake(10, 100, width, 50)];
    inputField.placeholder = @"请输入手机号码";
    inputField.layer.borderWidth = 1;
    inputField.delegate = self;
    inputField.layer.borderColor = [UIColor greenColor].CGColor;
    [self.view addSubview:inputField];

第三步:用我们定义好的规则和长度去限制输入内容,具体操作在代理方法- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string中操作。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    //用户可以进行删除操作
    if ([string isEqualToString:@""]) {
        return YES;
    }
    //长度限制
    if (textField.text.length > phonelength-1) {
        return NO;
    }
    //规则限制
    NSCharacterSet *cs;
    cs = [[NSCharacterSet characterSetWithCharactersInString:inputNumber] invertedSet];
    NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
    //按cs分离出数组,数组按@""分离出字符串
    BOOL canChange = [string isEqualToString:filtered];
    
    return canChange;
}

OK,一个手机号码输入框内容限制已经搞定了,好像也就那么回事,但是这有什么好思考的呢,额,听我慢慢道来。如果是下图这种情况或者类似的情况,大家又想到怎么用一种优雅的方式去处理呢?


二、笔者的方法思路:

写在前面:其实倒不是说这个方法多好,更多的是想抛砖引玉,看看大家是否有更好的方案,废话不多说,下面开始抛砖头喽。

这里主要是用到了runtime的给分类添加属性这一作用,在分类中将输入逻辑处理好,我们只需要在输入框输入的时候传入输入长度输入规则即可,最后再给分类添加一个block回调,将输入内容回调出来。
一、在UITextFiled分类.h中声明输入回调和输入使用方法:

//用户输入监听回调
typedef void(^UITextFieldEditValueChangeBlock)(UITextField * _Nonnull textField);
NS_ASSUME_NONNULL_BEGIN

@interface UITextField (TYExtention)

/// 对UITextFiled输入框的输入长度和规则做限制 并回调输入显示的结果
/// @param inputMax 输入框输入的最大长度
/// @param inputRules 输入规则限制
/// @param editValueBlock 输入回调
- (void)setTextFieldInputMax:(int)inputMax inputRules:(NSString *)inputRules editValueBlock:(UITextFieldEditValueChangeBlock)editValueBlock;

@end

NS_ASSUME_NONNULL_END

二、在UITextFiled分类.m文件中,主要是将- (void)setTextFieldInputMax:(int)inputMax inputRules:(NSString *)inputRules editValueBlock:(UITextFieldEditValueChangeBlock)editValueBlock方法实现出来。
既然是要为分类添加属性,非常明确的属性是三个:编辑文本回调、输入框输入的最大长度、输入规则。

@property (nonatomic, copy) UITextFieldEditValueChangeBlock editValueBlock;//编辑文本回调
@property (nonatomic, assign) int inputMax;//输入框输入的最大长度
@property (nonatomic, copy) NSString *inputRules;//输入规则限制

声明好这三个属性,实现set和get方法,才能为分类添加到属性,主要用到了两个函数。
实现set方法的函数:

OBJC_EXPORT void
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                         id _Nullable value, objc_AssociationPolicy policy)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);

实现get方法的函数:

OBJC_EXPORT id _Nullable
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
  • 实现编辑文本回调的set和get方法:
//*****输入监听******//
- (void)setEditValueBlock:(UITextFieldEditValueChangeBlock)editValueBlock{
    if (self.hasAddTarget == NO) {
        //避免重addTarget
        self.hasAddTarget = YES;
        [self addTarget:self action:@selector(textFiledValueEditChanged:) forControlEvents:UIControlEventEditingChanged];
    }
    objc_setAssociatedObject(self, &UITextFieldEditKey, editValueBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (UITextFieldEditValueChangeBlock)editValueBlock{
    return objc_getAssociatedObject(self, &UITextFieldEditKey);
}
  • 在editValueBlock的set方法中,添加了一个Target,监听用户的输入内容,并且把内容回调出去:
//*****输入监听  限制输入长度******//
- (void)textFiledValueEditChanged:(UITextField *)textField{
    //在有输入长度限制的情况下 限制输入长度
    if (self.inputMax) {
        if (textField.text.length > self.inputMax) {
            textField.text = [textField.text substringToIndex:self.inputMax];
        }
    }
    if (self.editValueBlock) {
        //如果实现了输入Block回调,将结果回调出去
        self.editValueBlock(textField);
    }
}
  • 实现输入最大长度的set和get方法:
//*****输入最大长度******//
- (void)setInputMax:(int)inputMax{
    objc_setAssociatedObject(self, @selector(inputMax), @(inputMax), OBJC_ASSOCIATION_ASSIGN);
}

- (int)inputMax{
    NSNumber *value = objc_getAssociatedObject(self, @selector(inputMax));
    return value.intValue;
}
  • 输入监听 输入规则的限制的set和get方法。在set方法中,让UITextFiled遵循了UITextFieldDelegate代理,方便我们在代理方法中处理输入规则:
//*****输入监听  输入规则的限制******//
- (void)setInputRules:(NSString *)inputRules{
    self.delegate = self;
    objc_setAssociatedObject(self, &UITextFieldInputRulesKey, inputRules, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)inputRules{
    return objc_getAssociatedObject(self, &UITextFieldInputRulesKey);
}
  • 在UITextFieldDelegate代理方法中,限制输入规则,输入规则为空字符串,表示没有限制:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    if ([self.inputRules isEqualToString:@""]) {
        return YES;
    }
    NSCharacterSet *cs;
    cs = [[NSCharacterSet characterSetWithCharactersInString:self.inputRules] invertedSet];
    NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
    //按cs分离出数组,数组按@""分离出字符串
    BOOL canChange = [string isEqualToString:filtered];
    
    return canChange;
}
  • 最后setTextFieldInputMax:(int)inputMax inputRules:(NSString *)inputRules editValueBlock:(UITextFieldEditValueChangeBlock)editValueBlock方法的实现,其实很简单,就是一个赋值的过程:
/// 对UITextFiled输入框的输入长度和规则做限制 并回调输入显示的结果
/// @param inputMax 输入框输入的最大长度
/// @param inputRules 输入规则限制
/// @param editValueBlock 输入回调
- (void)setTextFieldInputMax:(int)inputMax inputRules:(NSString *)inputRules editValueBlock:(UITextFieldEditValueChangeBlock)editValueBlock{
    self.inputRules = inputRules;
    self.inputMax = inputMax;
    self.editValueBlock = editValueBlock;
}

三、上面我们都封装好了,给大家看下是怎么调用的:

  • 先定义好你的输入规则和长度,如果规则不限制可传空字符串,不限制长度,传0即可。
int inputMax = normallength;
    NSString *inputRules = @"";
    self.inputFiled.keyboardType = UIKeyboardTypeDefault;
    if ([inputModel.title isEqualToString:@"身份证号"]) {
        inputMax = idCardlength;
        inputRules = idCardRules;
    }else if ([inputModel.title containsString:@"手机号"]){
        inputMax = phonelength;
        inputRules = numberRules;
        self.inputFiled.keyboardType = UIKeyboardTypeNumberPad;
    }else if ([inputModel.title containsString:@"银行卡号"]){
        inputMax = bankCardlength;
        inputRules = numberRules;
        self.inputFiled.keyboardType = UIKeyboardTypeNumberPad;
    }else if ([inputModel.title containsString:@"邮政编码"]){
        inputMax = postCodelength;
        inputRules = numberRules;
        self.inputFiled.keyboardType = UIKeyboardTypeNumberPad;
    }else if ([inputModel.title containsString:@"详细地址"]){
        inputMax = 0;
    }
  • 接着用定义好的输入长度和规则去调用封装好的方法即可:
//*******此处用法是 限制长度和输入规则 并且有输入结果回调*********//
    //*******inputMax为0 则输入长度不受限制  inputRules 为空字符串 @"" 输入规则不受限制*********//
    [self.inputFiled setTextFieldInputMax:inputMax inputRules:inputRules editValueBlock:^(UITextField * _Nonnull textField) {
        RYQLog(@"%@:%@", inputModel.title, textField.text);
        inputModel.content = textField.text;
    }];

结语:以上方法可能不是最好的,有好方法的朋友也别吝啬你的想法,一起分享出来吧,最后如果我的文章对你有所帮助,请帮我点个喜欢,3Q。戳这里,Demo地址。点击顺序:功能优化---UITextFiled输入限制。

相关文章

网友评论

      本文标题:iOS--UITextFiled输入限制的摸索

      本文链接:https://www.haomeiwen.com/subject/rdqzwhtx.html