ios UITextfield输入框限制:只能输入两位小数的价格格式或其他定制格式

前言

相信大家在ios移动应用开发中,经常会遇到这样的需求:给输入框限定输入格式,比如最多只能输入11个电话数字、只能输入小于指定值的价格格式(同时最多两位小数)等等。我看了大家基本上是实现UITextFieldDelegate协议的textField:shouldChangeCharactersInRange:replacementString:方法。但我发现很少对这种常见的需求实现进行封装。试想如果在开发中,一个view中有很多个UITextfield,而且还是需要不同的输入格式要求,那么我想在代理方法textField:shouldChangeCharactersInRange:replacementString:中的实现还是比较繁琐的,需要各种判断。

实现思路

为了解决上述问题,我想封装一个可以定制任何格式的UITextfileld 子类。
我准备也在代理方法textField:shouldChangeCharactersInRange:replacementString:里面进行字符判断,来控制输入框能否编辑。但为了更好的定制化,需要运用不同的正则表达式来匹配格式。同时这些判断逻辑我会写在的UITextfileld子类 --- BSLimitFormTextFild里面。具体步骤如下:

  1. 创建UITextfileld子类BSLimitFormTextFild,添加正则表达式文本的属性regex,用于控制各式各样的输入要求
    #import <UIKit/UIKit.h>

    static NSString *limitRegexPrice = @"^(\\d{0,5})(\\.[0-9]{0,2})?$"; // 最大值为         99999.99的价格正则表达式

    @interface BSLimitFormTextFild : UITextField

    @property (nonatomic, copy) NSString *regex; /**< 输入框内容的正则表达式 */


    @end

  1. 在BSLimitFormTextFild里面实现UITextfileld的代理方法textField:shouldChangeCharactersInRange:replacementString:,通过返回YES or NO来控制是否能够输入。
#import "BSLimitFormTextFild.h"
#import <objc/runtime.h>

@interface BSLimitFormTextFild() <UITextFieldDelegate>

@end
@implementation BSLimitFormTextFild

#pragma mark - Life Cycle && Initialize

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.delegate = self;
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    self.delegate = self;
}

#pragma mark - private action

- (BOOL)predicateWithRegex:(NSString *)regex
                      text:(NSString *)text
                 textField:(UITextField *)textField {
    
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    BOOL originMatch = YES;
    if (textField.text.length) {
        originMatch = [pred evaluateWithObject:textField.text];
    }
    if (originMatch) {
        //本来是符合规则的
        return [pred evaluateWithObject:text];
    }else{
        //本来不符合规则的话就清空(比如外部对该textFild set 一个不合规的text,当点击开始编辑时就要清空)
        textField.text = nil;
        return YES;
    }
}

#pragma mark - UITextFieldDelegate
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSString *toBeString = [textField.text stringByReplacingCharactersInRange:range withString:string];
    if (!toBeString.length) {
        return YES;
    }
    if (self.regex) {
        return [self predicateWithRegex:self.regex text:toBeString textField:textField];
    } else {
        return YES;
    }
}

  1. 最后,可能在使用BSLimitFormTextFild的时候,外部设置了delegate,比如用来监听UITextField的开始编辑、结束编辑的操作的话,这时会失效以上那些功能;所以我重写了- (void)setDelegate:(id<UITextFieldDelegate>)delegate 方法,如果外部设置了新delegate,又没有使用到textField:shouldChangeCharactersInRange:replacementString:方法的话,就自动给新代理动态添加该方法,如果用到了就不做任何操作。具体代码如下:

- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
    [super setDelegate:delegate];
    if (delegate != self) {
        if (![delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
            // 代理没有实现该代理方法,就动态帮他实现
            // b表示反悔bool值; b@:表示没有参数;  b@:@表示有一个参数(文档:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html)
            class_addMethod(delegate.class, @selector(textField:shouldChangeCharactersInRange:replacementString:), class_getMethodImplementation(self.class, @selector(textField:shouldChangeCharactersInRange:replacementString:)), "b@:@:@:@");
        } else {
            // 外部实现了该代理方法,就由外部决定是否可以编辑
        }
    }
}

demo演示


#import "ViewController.h"
#import "BSLimitFormTextFild.h"

@interface ViewController () <UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet BSLimitFormTextFild *nomalTF;
@property (weak, nonatomic) IBOutlet BSLimitFormTextFild *priceTF;
@property (weak, nonatomic) IBOutlet BSLimitFormTextFild *integerTF;
@property (weak, nonatomic) IBOutlet BSLimitFormTextFild *limitCountTF;
@property (weak, nonatomic) IBOutlet BSLimitFormTextFild *customTF;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 只能输入价格
    self.priceTF.regex = limitRegexPrice;
    // 只能输入整数
    self.integerTF.regex = limitRegexInteger;
    // 最多只能输入11位整数
    self.limitCountTF.regex = limitRegexIntegerCount;
    
    self.customTF.delegate = self;
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSString *toBeString = [textField.text stringByReplacingCharactersInRange:range withString:string];
    if (toBeString.length > 2) {
        NSLog(@"最多只能输入两个字");
        return NO;
    } else {
        return YES;
    }
}

demo效果

结语

demo源码我放在github上了https://github.com/LvBisheng/BSLimitFormTextFild和cocopods了(pod 'BSLimitFormTextFild', '~>1.0.0'),欢迎大家指导交流...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容