如何检查 UITextField 何时更改?

Posted

技术标签:

【中文标题】如何检查 UITextField 何时更改?【英文标题】:How do I check when a UITextField changes? 【发布时间】:2015-02-08 14:16:24 【问题描述】:

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

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

哪种方法有效,但只要按下文本字段就会启用topRightButton,我希望仅在实际输入文本时启用它?

【问题讨论】:

【参考方案1】:

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

目标-C

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

而textFieldDidChange方法是

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

【讨论】:

这对我来说崩溃了,我不明白为什么。 检查了多次。代表在 viewDidLoad 中紧接在它之前设置。行动是一个字母一个字母相同。一旦按下键盘按钮,应用程序就会崩溃。编辑:想通了!缺少动作中的分号。我假设它只需要与函数名称相同。 @FawadMasud 这现在在带有 XCode 7 的 ios 9 上的 Swift 2.0 中没有任何作用,它是否已被贬值,或者您知道当前的修复方法吗? @bibscy 是的,您必须遍历视图内的所有文本字段。 对于 Swift 4.2 它:Texttfield.addTarget(self, action: #selector(ViewControllerr.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)【参考方案2】:

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

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

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

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

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

【讨论】:

这是一个很好的解决方案,尤其是在处理由单独数据源管理的 tableViewCell 中的 UITextField 时。这种方法允许 viewController 直接响应(因此数据源不必响应和委托操作)。 太棒了 - 一个解决烦人问题的简单方法。您当然可以链接多个文本字段 可能比上面更好的答案,因为消除了添加@objc func。 好主意,我使用事件 DidEndEditing 这是最好的解决方案。谢谢@rmooney!【参考方案3】:

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)  


【讨论】:

【参考方案4】:

到目前为止我的处理方式: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

【讨论】:

当文本字段为空且用户单击退格键时,不会调用此方法。【参考方案5】:

斯威夫特 3

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

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案7】:

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

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

func textFieldDidChange(_ textField: UITextField) 


【讨论】:

【参考方案8】:

您可以从 UITextFieldDelegate 使用此委托方法。它会随着每个字符的变化而触发。

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

但是,这只会在进行更改之前触发(实际上,只有在您从此处返回 true 时才会进行更改)。

【讨论】:

这应该怎么写,因为我也尝试过这种方法并得出了相同的解决方案,即只有在激活 textField 后才会更改,而不是在文本实际更改后才更改?? 当您实现上述委托方法时,它会在您每次更改文本时触发。你只需要添加这段代码,self.textfield.delegate = self 对我来说,这种方法不起作用,因为您无法检查方法中的文本字段是否为空。主要是因为它根据文本字段是否可以更改返回真/假。因此,事件在文本字段有机会变空之前触发。 @LeviRoberts,您在此方法中引用了文本字段。所以你可以检查 textfield.text 是否为空。 你好像不明白。当它为空时,.isEmpty 方法在此方法有机会返回 true 之前不等于 true;告诉应用该文本字段应该更改。【参考方案9】:

斯威夫特 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

【讨论】:

【参考方案10】:

现在 iOS13+ 上提供了 UITextField 委托方法

optional func textFieldDidChangeSelection(_ textField: UITextField)

【讨论】:

这个方法是关于选择的,而不是实际的文本【参考方案11】:

也许使用 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 种方法..

    onError 已完成 onDisposed onNext

【讨论】:

要仅在文本字段成为第一响应者时接收真正更改的事件,而不是在文本字段成为第一响应者时,您必须在文本上使用 distinctUntilChanged。【参考方案12】:

斯威夫特 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") 
 

【讨论】:

【参考方案13】:
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 = ""
    

【讨论】:

【参考方案14】:

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

    对文本字段进行 Outlet 引用 将UITextFieldDelegate 分配给控制器类 配置你的TextField.delegate 实现您需要的任何功能

示例代码:

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
    

    .
    .
    .

【讨论】:

【参考方案15】:

斯威夫特 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 或您想要检测的任何内容更改事件。

【讨论】:

【参考方案16】:

这是使用 Swift 3 添加textField text change listener 的方法:

将您的班级声明为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 

【讨论】:

【参考方案17】:

如果您对 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

【讨论】:

【参考方案18】:

如果无法将 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 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

【讨论】:

【参考方案19】:

斯威夫特 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)
    

【讨论】:

以上是关于如何检查 UITextField 何时更改?的主要内容,如果未能解决你的问题,请参考以下文章

动态更改 UITextField 宽度取决于内容

如何检查输入值何时更改?

如何检查 UIImagePickerController 何时更改相机类型?

如何检查用户何时更改选择下拉列表的值?

更改 UItextField 的拼写检查/自动完成源

编辑时更改 uitextfield 返回键类型