Swift - 文本输入框内容改变时响应,并获取最新内容
(本文代码已升级至Swift3)
1,问题描述
当然我们还可以对 NSRange 做个扩展,添加个转换成 Range 的方法。这样我们就可以直接调用 String 的 replacingCharacters 方法获取最新值了。
1,问题描述
有时我们开发的时候需要先把“确认”按钮初始设置为不可用,当文本框中输入文字以后,再将输入按钮变为可用。


2,实现原理
(1)要检测文本框内容的变化,我们需要让新界面的Controller遵循一个文本协议 UITextFieldDelegate。
同时在 viewDidLoad 方法内将文本框的代理设置为当前实例。
然后实现 textFile 的 shouldChangeCharactersIn 方法就能在文本框将要变化的时候执行一些代码。
(2)但这个只是将要变化时执行,而不是变化后。比如在这个方法内打印出文本框的内容,会发现每当我们改变文本框的内容时,打印出来的是上一次的内容。
比如先输入1,打印出来是空。再输入2,文本框上是12,但打印出来却是1.
要获取最新内容,则需要 NSString 的 replacingCharacters 方法。
3,代码如下
import UIKit class ViewController: UIViewController ,UITextFieldDelegate{ @IBOutlet weak var button: UIButton! @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() textField.delegate = self } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let currentText = textField.text ?? "" let newText = (currentText as NSString).replacingCharacters(in: range, with: string) button.isEnabled = newText.characters.count > 0 return true } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
补充:实现NSRange到Range的转换
由于 shouldChangeCharactersIn 方法得到的 range 是 NSRange 类型,所以上面样例中我们先要将文本串转成 NSString,再调用 replacingCharacters 方法获取最新值。当然我们还可以对 NSRange 做个扩展,添加个转换成 Range 的方法。这样我们就可以直接调用 String 的 replacingCharacters 方法获取最新值了。
import UIKit class ViewController: UIViewController ,UITextFieldDelegate{ @IBOutlet weak var button: UIButton! @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() textField.delegate = self } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let currentText = textField.text ?? "" let newText = currentText.replacingCharacters(in: range.toRange(string: currentText), with: string) button.isEnabled = newText.characters.count > 0 return true } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } } //扩展NSRange,添加转换成Range的方法 extension NSRange { func toRange(string: String) -> Range<String.Index> { let startIndex = string.index(string.startIndex, offsetBy: self.location) let endIndex = string.index(startIndex, offsetBy: self.length) return startIndex..<endIndex } }
还有更简单的实现方法。
1,通过编辑事件实现
这里感谢网友王沫的提醒,其实响应输入框的编辑事件(allEditingEvents)就可以获取最新的内容。import UIKit class ViewController: UIViewController { @IBOutlet weak var button: UIButton! @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() textField.addTarget(self, action: #selector(textChange(_:)), for: .allEditingEvents) } func textChange(_ textField:UITextField) { self.button.isEnabled = (textField.text?.characters.count)!>0 } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
2,监听文字改变通知
这里感谢网友嘿喂狗的提醒,通过监听 textField 文字改变的通知,也可以获取最新的内容。import UIKit class ViewController: UIViewController { @IBOutlet weak var button: UIButton! @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default .addObserver(self, selector: #selector(ViewController.textChange(_:)), name: .UITextFieldTextDidChange, object: nil) } func textChange(_ notification: Notification) { self.button.isEnabled = (textField.text?.characters.count)!>0 } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
感谢楼主。。终于知道了shouldChangeCharactersIn 每次只会打印 上一次的字符串了。。
-。- 还有个方法也可以补充哦。用通知也能实现
也可采用以下方法:
textField .addTarget(self, action: #selector(textChange(_:)), for: .allEditingEvents)
func textChange(_ textField:UITextField) {
self.button.isEnabled = (textField.text?.characters.count)!>10
}
航哥,这篇文章很实用,可是在更新swift3后不能用了,我是个初学者,摸索半天没搞定,还请详细讲解一下,谢谢