当前位置: > > > Swift - 文本输入框内容改变时响应,并获取最新内容

Swift - 文本输入框内容改变时响应,并获取最新内容

(本文代码已升级至Swift3)

1,问题描述
有时我们开发的时候需要先把“确认”按钮初始设置为不可用,当文本框中输入文字以后,再将输入按钮变为可用。
             

2,实现原理
(1)要检测文本框内容的变化,我们需要让新界面的Controller遵循一个文本协议 UITextFieldDelegate
同时在 viewDidLoad 方法内将文本框的代理设置为当前实例。
然后实现 textFileshouldChangeCharactersIn 方法就能在文本框将要变化的时候执行一些代码。

(2)但这个只是将要变化时执行,而不是变化后。比如在这个方法内打印出文本框的内容,会发现每当我们改变文本框的内容时,打印出来的是上一次的内容。
比如先输入1,打印出来是空。再输入2,文本框上是12,但打印出来却是1.
要获取最新内容,则需要 NSStringreplacingCharacters 方法。

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 方法得到的 rangeNSRange 类型,所以上面样例中我们先要将文本串转成 NSString,再调用 replacingCharacters 方法获取最新值。
当然我们还可以对 NSRange 做个扩展,添加个转换成 Range 的方法。这样我们就可以直接调用 StringreplacingCharacters 方法获取最新值了。
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()
    }
}
评论3
  • 3楼
    2017-02-21 16:01
    嘿喂狗

    感谢楼主。。终于知道了shouldChangeCharactersIn 每次只会打印 上一次的字符串了。。
    -。- 还有个方法也可以补充哦。用通知也能实现

    站长回复

    不客气。我也谢谢你补充的方法,我这里也把文章更新了下。

  • 2楼
    2017-01-11 13:40
    王沫

    也可采用以下方法:
    textField .addTarget(self, action: #selector(textChange(_:)), for: .allEditingEvents)
    func textChange(_ textField:UITextField) {
    self.button.isEnabled = (textField.text?.characters.count)!>10

    }

    站长回复

    谢谢提醒,这个方法好,我把文章更新下。

  • 1楼
    2016-11-25 16:32
    YYYY

    航哥,这篇文章很实用,可是在更新swift3后不能用了,我是个初学者,摸索半天没搞定,还请详细讲解一下,谢谢

    站长回复

    我把文章更新了,你可以再看下。