最近因为项目的需要,需要很多输入框输入填写信息,像手机号必须输入数字,并且长度不能超过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输入限制。
网友评论