如何检查 UITextField 何时更改?

How do I check when a UITextField changes?

我正在尝试检查文本字段何时更改,这也等同于用于 textView 的函数 - textViewDidChange 到目前为止我已经这样做了:

  func textFieldDidBeginEditing(textField: UITextField) {
        if self.status.text == "" && self.username.text == "" {
            self.topRightButton.enabled = false
        } else {   
            self.topRightButton.enabled = true
        }
    }

哪种有效,但是 topRightButton 在按下文本字段后立即启用,我希望它仅在实际输入文本时启用?

SWIFT

Swift 4.2

textfield.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)

@objc func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 3 & swift 4.1

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), for: .editingChanged)

func textFieldDidChange(_ textField: UITextField) {

}

SWIFT 2.2

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged)

func textFieldDidChange(textField: UITextField) {
    //your code
}

OBJECTIVE-C

[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

而 textFieldDidChange 方法是

-(void)textFieldDidChange :(UITextField *) textField{
    //your code
}

您可以使用 UITextFieldDelegate 中的委托方法。每次字符更改都会触发。

(Objective C) textField:shouldChangeCharactersInRange:replacementString:
(Swift) textField(_:shouldChangeCharactersInRange:replacementString:)

然而,这只会在 进行更改之前触发(实际上,只有当您从此处 return 为真时,才会进行更改)。

到目前为止我的处理方式:在UITextFieldDelegate

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    // text hasn't changed yet, you have to compute the text AFTER the edit yourself
    let updatedString = (textField.text as NSString?)?.stringByReplacingCharactersInRange(range, withString: string)

    // do whatever you need with this updated string (your code)


    // always return true so that changes propagate
    return true
}

Swift4 版本

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
    return true
}

您可以在界面生成器中进行此连接。

  1. 在故事板中,单击屏幕顶部的助理编辑器(中间的两个圆圈)。

  2. Ctrl + 单击界面生成器中的文本字段。

  3. 从 EditingChanged 拖动到助手视图中的视图控制器内部 class。

  4. 为您的函数命名(例如 "textDidChange")并单击“连接”。

Swift 3

 textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(sender:)), for: UIControlEvents.editingChanged)

这是您可以使用 Swift 3:

添加 textField text change listener 的方法

将您的 class 声明为 UITextFieldDelegate

override func viewDidLoad() {
    super.viewDidLoad()

    textField.delegate = self

    textField.addTarget(self, action: #selector(UITextFieldDelegate.textFieldShouldEndEditing(_:)), for: UIControlEvents.editingChanged)
}

然后按照传统方式添加一个 textFieldShouldEndEditing 函数:

func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { // do stuff
        return true 
}

textField(_:shouldChangeCharactersIn:replacementString:) 在 Xcode 8 为我工作,Swift 3 如果你想检查每一个按键。

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    // Whatever code you want to run here.
    // Keep in mind that the textfield hasn't yet been updated,
    // so use 'string' instead of 'textField.text' if you want to
    // access the string the textfield will have after a user presses a key

    var statusText = self.status.text
    var usernameText = self.username.text

    switch textField{
    case self.status:
        statusText = string
    case self.username:
        usernameText = string
    default:
        break
    }

    if statusText == "" && usernameText == "" {
        self.topRightButton.enabled = false
    } else {   
        self.topRightButton.enabled = true
    }

    //Return false if you don't want the textfield to be updated
    return true
}

Swift 5.0

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: .editingChanged)

及处理方式:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 4.0

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: UIControlEvents.editingChanged)

及处理方式:

@objc func textFieldDidChange(_ textField: UITextField) {

}

Swift 3.0

textField.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged)

及处理方式:

func textFieldDidChange(textField: UITextField) { 

}

Swift 3.0.1+(其他一些 swift 3.0 答案不是最新的)

textField.addTarget(self, action: #selector(ViewController.textFieldDidChange(_:)),
                          for: UIControlEvents.editingChanged)

func textFieldDidChange(_ textField: UITextField) {

}

也许使用 RxSwift?

需要

pod 'RxSwift',    '~> 3.0'
pod 'RxCocoa',    '~> 3.0'

显然添加导入

import RxSwift
import RxCocoa

所以你有 textfield : UITextField

let observable: Observable<String?> = textField.rx.text.asObservable()
observable.subscribe(
            onNext: {(string: String?) in
                print(string!)
        })

你还有其他3种方法..

  1. onError
  2. 已完成
  3. onDisposed
  4. onNext

swift 4

在 viewDidLoad() 中:

    //ADD BUTTON TO DISMISS KEYBOARD

    // Init a keyboard toolbar 
    let toolbar = UIView(frame: CGRect(x: 0, y: view.frame.size.height+44, width: view.frame.size.width, height: 44))
    toolbar.backgroundColor = UIColor.clear

    // Add done button
    let doneButt = UIButton(frame: CGRect(x: toolbar.frame.size.width - 60, y: 0, width: 44, height: 44))
    doneButt.setTitle("Done", for: .normal)
    doneButt.setTitleColor(MAIN_COLOR, for: .normal)
    doneButt.titleLabel?.font = UIFont(name: "Titillium-Semibold", size: 13)
    doneButt.addTarget(self, action: #selector(dismissKeyboard), for: .touchUpInside)
    toolbar.addSubview(doneButt)

    USDTextField.inputAccessoryView = toolbar

添加此功能:

    @objc func dismissKeyboard() {
      //Causes the view (or one of its embedded text fields) to resign the first responder status.
      view.endEditing(true)
    }

Swift 4

符合UITextFieldDelegate

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // figure out what the new string will be after the pending edit
    let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)

    // Do whatever you want here


    // Return true so that the change happens
    return true
}

Swift 4

textField.addTarget(self, action: #selector(textIsChanging), for: UIControlEvents.editingChanged)

@objc func textIsChanging(_ textField:UITextField) {

 print ("TextField is changing")

}

如果你想在用户完全输入后进行更改(一旦用户关闭键盘或按回车键就会调用)。

textField.addTarget(self, action: #selector(textDidChange), for: UIControlEvents.editingDidEnd)

 @objc func textDidChange(_ textField:UITextField) {

       print ("TextField did changed") 
 }
txf_Subject.addTarget(self, action:#selector(didChangeFirstText), for: .editingChanged)

@objc func didChangeText(textField:UITextField) {
    let str = textField.text
    if(str?.contains(" "))!{
        let newstr = str?.replacingOccurrences(of: " ", with: "")
        textField.text = newstr
    }
}

@objc func didChangeFirstText(textField:UITextField) {
    if(textField.text == " "){
        textField.text = ""
    }
}

您应该按照以下步骤操作:

  1. 引用文本字段的 Outlet
  2. 将 UITextFieldDelegate 分配给控制器 class
  3. 配置yourTextField.delegate
  4. 实现您需要的任何功能

示例代码:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var yourTextFiled : UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        yourTextFiled.delegate = self
    }


    func textFieldDidEndEditing(_ textField: UITextField) {
        // your code
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        // your code
    }

    .
    .
    .
}

Swift 4.2

在viewDidLoad中写这个

// to detect if TextField changed
TextField.addTarget(self, action: #selector(textFieldDidChange(_:)),
                                   for: UIControl.Event.editingChanged)

在 viewDidLoad 之外写这个

@objc func textFieldDidChange(_ textField: UITextField) {
    // do something
}

您可以通过 UIControl.Event.editingDidBegin 或任何您想检测的方式更改事件。

以防万一您对 SwiftUI 解决方案感兴趣,这个对我有用:

 TextField("write your answer here...",
            text: Binding(
                     get: {
                        return self.query
                       },
                     set: { (newValue) in
                        self.fetch(query: newValue) // any action you need
                                return self.query = newValue
                      }
            )
  )

我不得不说这不是我的主意,我是在这个博客上读到的:SwiftUI binding: A very simple trick

如果无法将 addTarget 绑定到您的 UITextField,我建议您按照上面的建议绑定其中一个,并在 shouldChangeCharactersIn 方法的末尾插入执行代码。

nameTextField.addTarget(self, action: #selector(RegistrationViewController.textFieldDidChange(_:)), for: .editingChanged)

@objc func textFieldDidChange(_ textField: UITextField) {
    if phoneNumberTextField.text!.count == 17 && nameTextField.text!.count > 0 {
        continueButtonOutlet.backgroundColor = UIColor(.green)
    } else {
        continueButtonOutlet.backgroundColor = .systemGray
    }
}

并且在调用 shouldChangeCharactersIn func.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    guard let text = textField.text else {
        return true
    }
    let lastText = (text as NSString).replacingCharacters(in: range, with: string) as String

    if phoneNumberTextField == textField {
        textField.text = lastText.format("+7(NNN)-NNN-NN-NN", oldString: text)
        textFieldDidChange(phoneNumberTextField)
        return false
    }
    return true
}

iOS13+

现在有一个 UITextField 委托方法可用
optional func textFieldDidChangeSelection(_ textField: UITextField)