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)
非中文或英文的不好使啊,还能输入数字,符号呢
站长回复:不是吧,我又测试了下是无法输入数字和符号的。
其实在哪里添加和移除通知一直都是个问题,我看在这段代码里添加和移除是放在willAppear和DidAppear中的,如果不考虑该控制器可能会被循环引用,将移除放在析构函数deinit里更好,至于添加通知就仁者见仁智者见智了
站长回复:你说的有道理,这个还是要根据实际项目,具体情况具体分析。
RxSwift来个呗
站长回复:这个肯定要写的。就是RxSwift东西比较多,需要找个时间好好整整。