iOS 实现 UITextField 字数或输入类型限制终极方案

我们知道 iOS 自带的 UITextField 并没有提供任何有关字数限制的属性,如果想实现这个功能,最简单的办法大家有可能想到使用 delegate 实现 textField(_: , shouldChangeCharactersInRange _: , replacementString _:) 代理方法,在这个方法中我们只需得到最终替换完毕的结果即可对其进行字数或有效性的检查,如果不符合要求就直接返回 false

这个代理方法将会在用户修改输入框内文字时触发,传入的 range 是用户已选中的文本区间,string 则是用户输入的文字,而不是最终完整的文本。所以我们要先自己用新文本替换一下原来的文本。

代码如下:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let replacedString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
        
        if /* Validate replacedString */ {
            return false
        }
        
        return true
}

注意这里有个小坑,就是如果你使用了 Emoji 表情或者其他西方文字,会出现运行时的异常,这是由于 Swift 和 Objective-C 对于字符串实现不同造成的,所以我并没有使用 Swift 提供的 String 类型,而是将其强制转换成 NSString,然后再进行字符串替换处理,以解决上述的问题。

但是问题并没有解决,当我们使用中文键盘的时候,连续按两下空格会输入句号,而且上面的代理方法并不能拦截这个句号的输入。所以我们只能曲线救国,由于 iOS 还提供了一个 Notification 叫做 UITextFieldTextDidChangeNotification,监听这个通知,然后在文本改变之后再进行一次检验。

我采用的方法是先修改上面的代理方法为:

func validate(string: String) -> Bool {
        if string.isEmpty {
            return true
        }
        
        if let regex = try? NSRegularExpression(pattern: "^[0-9]{0,4}.{0,1}[0-9]{0,2}$", options: .CaseInsensitive) {
            return regex.matchesInString(string, options: .WithoutAnchoringBounds, range: NSMakeRange(0, string.characters.count)).count > 0
        }
        
        return false
    }
    
    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let replacedString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
        
        if !self.validate(replacedString) {
            return false
        } else {
            self.lastValidText = replacedString
        }
        
        return true
}

可以看到我使用了一个validate(_:) 函数对文本进行检验,这样需求有变更时我们只需修改这个函数即可,本例子中我使用了一个正则表达式来检验用户的输入,当然实际使用时大家也可以去检验字数等。

然后我会保存每次合法的输入,当输入完毕时,下面方法将会调用:

func textFieldDidChangeText() {
        if !self.validate(self.textField?.text ?? "") {
            self.textField?.text = self.lastValidText
        }
}

判断文本修改完毕后的值是否合法,如果不合法就替换回上一次合法的输入,这样我们就完美的实现了字数、输入限制了。

我们还可以对这些方法进行封装:

然后使用时就可以这样:

以上。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,200评论 19 139
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 14,755评论 4 61
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 176,695评论 25 709
  • � 我的座右铭是:假如你即将死去! 乔布斯死后,对我触动很大。因为无知与浅薄,这么多年了,很多名人我都是在他死了...
    假如明天阅读 3,315评论 1 1
  • 前些日子,我在重庆,入秋以后,重庆的天气就变了脸,从热情似火转为阴雨绵绵,作为一个酷爱阳光的人,特别不习惯这种阴天...
    一匹来自南方的狼阅读 4,647评论 7 4

友情链接更多精彩内容