返回 导航

Swift

hangge.com

Swift - 限制TextField只能输入中文(附:中文字数的限制)

作者:hangge | 2017-12-29 08:10

1,效果图

这里对界面上的 UITextField 做了输入限制,只能输入中文。不接受除中文外的其他一切字符(包括英文、数字、符号等),即使粘贴进来也不行。

2,实现原理

(1)要对 textField 的输入做限制,无非有两种方法。一种是使用 shouldChangeCharactersIn 这个 textField 的代理方法。该方法会在每次 textfield 有输入的时候被调用,我们只需对每次输入的内容进行判断,看是否符合条件即可。
  • 符合条件的return true,相应的文字会成功输入到 textField 中。
  • 不符合条件的return false,相应的文字无法输入到 textField 中。
但如果我们只允许输入中文的话就会有问题。因为当我们使用系统的拼音输入法输入中文时,首先需要输入拼音字母,这个叫做 marked text(见下图)。

marked text 也是会被 shouldChangeCharactersIn 方法强制获取到的。只要打出拼音的第一个英文字母,就会被该方法截取,我们无法判断这个字母是英文字母还是拼音字母。如果禁止英文输入的话,那么中文也就没法打出来了。

(2)所以我们只能使用另一种方法:监听 textField UITextFieldTextDidChangeNotification 通知事件,在事件响应函数里进行如下工作:
  • 先判断当前是否有 markedtext,有的话我们不做任何动作。
  • 使用正则过滤掉 textField 里非中文的字符,然后再将结果重新赋给 textField
  • 进行上面操作前要记下光标的位置,在赋值后再还原光标位置。否则如果在中间输入文字后,光标会自动跳到末尾。

3,样例代码

import UIKit

class ViewController: UIViewController {
    
    //文本输入框
    var textField:UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //初始化文本输入框
        textField = UITextField(frame: CGRect(x:20, y:100, width:200, height:30))
        textField.borderStyle = .roundedRect
        self.view.addSubview(textField)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        //监听textField内容改变通知
        NotificationCenter.default.addObserver(self,
            selector: #selector(self.greetingTextFieldChanged),
            name:NSNotification.Name(rawValue:"UITextFieldTextDidChangeNotification"),
            object: self.textField)
    }

    //textField内容改变通知响应
    @objc func greetingTextFieldChanged(obj: Notification) {
        //非markedText才继续往下处理
        guard let _: UITextRange = textField.markedTextRange else{
            //当前光标的位置(后面会对其做修改)
            let cursorPostion = textField.offset(from: textField.endOfDocument,
                                                 to: textField.selectedTextRange!.end)
            //判断非中文的正则表达式
            let pattern = "[^\\u4E00-\\u9FA5]"
            //替换后的字符串(过滤调非中文字符)
            let str = textField.text!.pregReplace(pattern: pattern, with: "")
            textField.text = str
            
            //让光标停留在正确位置
            let targetPostion = textField.position(from: textField.endOfDocument,
                                                   offset: cursorPostion)!
            textField.selectedTextRange = textField.textRange(from: targetPostion,
                                                              to: targetPostion)
            return
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        //移除textField内容改变通知监听
        NotificationCenter.default.removeObserver(self,
            name:NSNotification.Name(rawValue: "UITextFieldTextDidChangeNotification"),
            object: self.textField)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

extension String {
    //使用正则表达式替换
    func pregReplace(pattern: String, with: String,
                     options: NSRegularExpression.Options = []) -> String {
        let regex = try! NSRegularExpression(pattern: pattern, options: options)
        return regex.stringByReplacingMatches(in: self, options: [],
                                              range: NSMakeRange(0, self.count),
                                              withTemplate: with)
    }
}
常用的一些正则表达式:
  • 非中文:[^\\u4E00-\\u9FA5]
  • 非英文:[^A-Za-z]
  • 非数字:[^0-9]
  • 非中文或英文:[^A-Za-z\\u4E00-\\u9FA5]
  • 非英文或数字:[^A-Za-z0-9]
  • 非因为或数字或下划线:[^A-Za-z0-9_]

附:增加中文字数限制

下面代码在前面的基础上再增加个字数限制:textField 不仅只能输入中文,而且最多只能输入 10 个字。 (这个同样是监听 textField UITextFieldTextDidChangeNotification 通知事件来实现,高亮部分表示新增加的代码)
//textField内容改变通知响应
@objc func greetingTextFieldChanged(obj: Notification) {
    //非markedText才继续往下处理
    guard let _: UITextRange = textField.markedTextRange else{
        //当前光标的位置(后面会对其做修改)
        let cursorPostion = textField.offset(from: textField.endOfDocument,
                                             to: textField.selectedTextRange!.end)
        //判断非中文的正则表达式
        let pattern = "[^\\u4E00-\\u9FA5]"
        //替换后的字符串(过滤调非中文字符)
        var str = textField.text!.pregReplace(pattern: pattern, with: "")
        //如果长度超过限制则直接截断
        if str.count > 10 {
            str = String(str.prefix(10))
        }
        textField.text = str
        
        //让光标停留在正确位置
        let targetPostion = textField.position(from: textField.endOfDocument,
                                               offset: cursorPostion)!
        textField.selectedTextRange = textField.textRange(from: targetPostion,
                                                          to: targetPostion)
        return
    }
}
评论

全部评论(3)

回到顶部