当UITextField发生改变时,我该如何进行检查?

367

我正在尝试检查文本字段何时更改,相当于用于textView的函数textViewDidChange,到目前为止我已经做到了这一点:

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

这种方法可以工作,但是topRightButton会在用户点击文本框时立即启用,我希望它只有在实际输入文本时才启用。

21个回答

892

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
}

这对我来说崩溃了,我不明白为什么。 - Levi Roberts
1
已经多次检查过。委托在 viewDidLoad 之前立即设置。操作是逐字相同的。应用程序在按下键盘按钮时立即崩溃。编辑:问题解决了!操作内缺少分号。我以为它只需要与函数名称相同。 - Levi Roberts
@CodyWeaver 我刚在XCode 7,iOS 9上检查了一下,它可以正常工作。确保您命名的函数中没有拼写错误。 - Fawad Masud
1
@bibscy 是的,你必须循环遍历视图中的所有文本字段。 - Fawad Masud
1
对于Swift 4.2,它是: Texttfield.addTarget(self, action: #selector(ViewControllerr.textFieldDidChange(_:)), for: UIControl.Event.editingChanged) - Exitare
显示剩余15条评论

154

你可以在界面构建器中进行这个连接。

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

  2. 在界面构建器中,按住Ctrl键并单击文本框。

  3. 从EditingChanged拖动到助理视图中的视图控制器类内部。 Making connection

  4. 给你的函数命名(例如"textDidChange")并点击连接。 Naming function


3
如果在一个由独立数据源管理的tableViewCell中处理UITextField,这是一个很好的解决方案,特别是。这种方法允许viewController直接响应(因此数据源不必响应和委派操作)。 - wuf810
1
太好了 - 对一个烦人的问题来说是个简单的解决方案。当然你可以链接多个文本字段。 - Jeremy Andrews
1
可能比上面更好的答案,因为消除了添加 @objc func 的需要。 - Matthew Bradshaw
好主意,我使用了 DidEndEditing 事件。 - Puji Wahono
使用IBActions更容易,这可能应该是最佳答案。 - David Chopin
显示剩余2条评论

91

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) { 

}

41
到目前为止,我处理它的方式是:在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
当文本框为空且用户点击退格键时,此函数不会被调用。 - Matthew Mitchell

14

Swift 3

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

10

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
}

8

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
}

7

Swift 3.0.1+(其他一些Swift 3.0的答案已经过时)

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

func textFieldDidChange(_ textField: UITextField) {

}

6
您可以使用UITextFieldDelegate中的此代理方法。它会在每次字符更改时触发。
(Objective C) textField:shouldChangeCharactersInRange:replacementString:
(Swift) textField(_:shouldChangeCharactersInRange:replacementString:)

然而,这只会在更改之前触发(确实,只有在从这里返回true时才会进行更改)。


1
这应该如何编写?我也尝试过这种方法,并得出了相同的解决方案,即它只在textField被激活时更改一次,而不是在文本实际更改时更改。 - user4184036
当您实现上述委托方法时,它会在每次更改文本时触发。您只需要添加此代码,self.textfield.delegate = self。 - Abubakr Dar
对我来说,这种方法不起作用,因为你无法在方法内部检查textfield是否为空。主要是因为它根据textfield是否可以更改返回true/false。因此,在textfield有机会变为空之前,事件就已经触发了。 - Levi Roberts
@LeviRoberts,您在此方法中引用了文本字段。因此,您可以检查textfield.text是否为空。 - Abubakr Dar
你似乎不理解。当它为空时,.isEmpty方法直到此方法有机会返回true之后才等同于true;告诉应用程序文本字段应该更改。 - Levi Roberts
根据协议参考; “询问委托人指定的文本是否应更改。”https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextFieldDelegate_Protocol/#//apple_ref/occ/intfm/UITextFieldDelegate/textField:shouldChangeCharactersInRange:replacementString: - Levi Roberts

3
也许可以使用 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!)
        })

你还有其他三种方法..

  1. onError(出错时)
  2. onCompleted(完成时)
  3. onDisposed(已处理时)
  4. onNext(进行中)

为了仅接收真正更改的事件,而不是文本字段成为第一响应者时也接收事件,您必须在文本上使用distinctUntilChanged。 - RealNmae

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接