我如何检测文本字段中的任何文本变化?委托方法shouldChangeCharactersInRange适用于某些东西,但它并没有完全满足我的需求。因为在它返回YES之前,textField文本对其他观察器方法是不可用的。

例如,在我的代码calculateAndUpdateTextFields没有得到更新的文本,用户已经键入。

是他们的任何方式得到类似textChanged Java事件处理程序。

- (BOOL)textField:(UITextField *)textField 
            shouldChangeCharactersInRange:(NSRange)range 
            replacementString:(NSString *)string 
{
    if (textField.tag == kTextFieldTagSubtotal 
        || textField.tag == kTextFieldTagSubtotalDecimal
        || textField.tag == kTextFieldTagShipping
        || textField.tag == kTextFieldTagShippingDecimal) 
    {
        [self calculateAndUpdateTextFields];

    }

    return YES;
}

从正确的方法做uitextfield文本更改回调:

我捕获发送到UITextField控件的字符,就像这样:

// Add a "textFieldDidChange" notification method to the text field control.

在objective - c中:

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

迅速:

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

然后在textFieldDidChange方法中,您可以检查textField的内容,并根据需要重新加载您的表视图。

你可以使用它并将calculateAndUpdateTextFields作为你的选择器。


XenElement的答案是正确的。

以上也可以在接口构建器中通过右键单击UITextField并将“Editing Changed”发送事件拖放到你的子类单元中来完成。


正如这里所述:UITextField文本更改事件,似乎在iOS 6 (iOS 6.0和6.1检查),仅通过观察UITextFieldTextDidChangeNotification是不可能完全检测到UITextField对象的更改的。

现在似乎只有那些由内置的iOS键盘直接做出的改变才会被追踪。这意味着如果你改变你的UITextField对象仅仅通过调用这样的东西:myUITextField。Text = @"any_text",你将不会收到任何更改的通知。

我不知道这是一个错误还是故意的。似乎是一个bug,因为我在文档中没有找到任何合理的解释。这里也说明了:UITextField文本更改事件。

我的“解决方案”,这实际上是张贴一个通知,我自己的每一个改变,我对我的UITextField(如果这个改变是没有使用内置的iOS键盘)。就像这样:

myUITextField.text = @"I'm_updating_my_UITextField_directly_in_code";

NSNotification *myTextFieldUpdateNotification  = 
  [NSNotification notificationWithName:UITextFieldTextDidChangeNotification
                  object:myUITextField];

[NSNotificationCenter.defaultCenter 
  postNotification:myTextFieldUpdateNotification];

这样,当你改变UITextField对象的.text属性时,你100%有信心收到相同的通知,无论是在代码中“手动”更新还是通过内置的iOS键盘更新。

考虑到这一点很重要,因为这不是一个记录在案的行为,这种方法可能会导致在UITextField对象中收到两个相同更改的通知。这取决于你的需要(当你的UITextField。文本更改)这可能会给您带来不便。

一个稍微不同的方法是发布一个自定义通知(这是一个自定义名称,而不是UITextFieldTextDidChangeNotification),如果你真的需要知道这个通知是你的还是“ios制作的”。

编辑:

我刚刚发现了一个我认为更好的方法:

这涉及到Objective-C (http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177-BCICJDHA)的键值观察(KVO)特性。

基本上,你把自己注册为一个属性的观察者,如果这个属性发生了变化,你会得到通知。它的“原理”与NSNotificationCenter的工作方式非常相似,这是这种方法在iOS 6中自动工作的主要优势(没有任何特殊的调整,如必须手动发布通知)。

对于我们的uitextfield场景,如果你将这段代码添加到包含文本字段的UIViewController中,这就可以了:

static void *myContext = &myContext;

- (void)viewDidLoad {
  [super viewDidLoad];

  //Observing changes to myUITextField.text:
  [myUITextField addObserver:self forKeyPath:@"text"
    options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld 
    context:myContext];

}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
change:(NSDictionary *)change context:(void *)context {

  if(context == myContext) {
    //Here you get notified every time myUITextField's "text" property is updated
    NSLog(@"New value: %@ - Old value: %@",
      [change objectForKey:NSKeyValueChangeNewKey],
      [change objectForKey:NSKeyValueChangeOldKey]);
  }
  else 
    [super observeValueForKeyPath:keyPath ofObject:object 
      change:change context:context];

}

关于“上下文”管理的答案:https://stackoverflow.com/a/12097161/2078512

注意:似乎当你在用内置的iOS键盘编辑UITextField的过程中,文本字段的“text”属性不会随着每一个新输入/删除的字母而更新。相反,在您重新指定文本字段的第一响应器状态后,文本字段对象将“作为一个整体”进行更新。


设置事件监听器。

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

真正倾听:

- (void)textFieldDidChange:(UITextField *)textField {
    NSLog(@"text changed: %@", textField.text);
}

我解决了改变shouldChangeChractersInRange行为的问题。如果你返回NO,这些更改不会被iOS内部应用,相反,你有机会手动更改它,并在更改后执行任何操作。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //Replace the string manually in the textbox
    textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
    //perform any logic here now that you are sure the textbox text has changed
    [self didChangeTextInTextField:textField];
    return NO; //this make iOS not to perform any action
}

这里是相同的swift版本。

textField.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)

func textFieldDidChange(textField: UITextField) {

}

谢谢


[[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(didChangeTextViewText:) 
name:UITextFieldTextDidChangeNotification object:nil];



- (void) didChangeTextViewText {
 //do something
}

迅速:

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

然后,实现回调函数:

@objc final private func yourHandler(textField: UITextField) {
    print("Text changed")
}

您应该使用通知来解决这个问题,因为其他方法将侦听输入框而不是实际输入,特别是当您使用中文输入法时。 在viewDidload

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:)
                                                 name:@"UITextFieldTextDidChangeNotification"
                                               object:youTarget];

然后

- (void)textFiledEditChanged:(NSNotification *)obj {
UITextField *textField = (UITextField *)obj.object;
NSString *toBestring = textField.text;
NSArray *currentar = [UITextInputMode activeInputModes];
UITextInputMode *currentMode = [currentar firstObject];
if ([currentMode.primaryLanguage isEqualToString:@"zh-Hans"]) {
    UITextRange *selectedRange = [textField markedTextRange];
    UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
    if (!position) {
        if (toBestring.length > kMaxLength)
            textField.text =  toBestring;
} 

}

最后,你跑,就完了。


Swift测试版本:

//Somewhere in your UIViewController, like viewDidLoad(){ ... }
self.textField.addTarget(
        self, 
        action: #selector(SearchViewController.textFieldDidChange(_:)),
        forControlEvents: UIControlEvents.EditingChanged
)

参数解释道:

self.textField //-> A UITextField defined somewhere in your UIViewController
self //-> UIViewController
.textFieldDidChange(_:) //-> Can be named anyway you like, as long as it is defined in your UIViewController

然后在你的UIViewController中添加你上面创建的方法:

//Gets called everytime the text changes in the textfield.
func textFieldDidChange(textField: UITextField){

    print("Text changed: " + textField.text!)

}

我们可以很容易地从Storyboard中配置,按CTRL拖动@IBAction并更改事件,如下所示:


对于Swift 3.0:

let textField = UITextField()

textField.addTarget(
    nil,
    action: #selector(MyClass.textChanged(_:)),
    for: UIControlEvents.editingChanged
)

像这样使用类:

class MyClass {
    func textChanged(sender: Any!) {

    }
}

斯威夫特3.1:

选择器:类名。MethodName

  cell.lblItem.addTarget(self, action: #selector(NewListScreen.fieldChanged(textfieldChange:)), for: .editingChanged)

  func fieldChanged(textfieldChange: UITextField){

    }

Swift 3版本:

class SomeClass: UIViewController, UITextFieldDelegate { 

   @IBOutlet weak var aTextField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        aTextField.delegate = self
        aTextField.addTarget(self, action: #selector(SignUpVC.textFieldDidChange), for: UIControlEvents.editingChanged)        
    }

   func textFieldDidChange(_ textField: UITextField) {

       //TEXT FIELD CHANGED..SECRET STUFF

   }

}

不要忘记设置委托。


关闭:

   class TextFieldWithClosure: UITextField {
    var targetAction: (() -> Void)? {
        didSet {
            self.addTarget(self, action: #selector(self.targetSelector), for: .editingChanged)
        }
    }

    func targetSelector() {
        self.targetAction?()
    }
    }

和使用

textField.targetAction? = {
 // will fire on text changed
 }

斯威夫特4

func addNotificationObservers() {

    NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChangeAction(_:)), name: .UITextFieldTextDidChange, object: nil)

}

@objc func textFieldDidChangeAction(_ notification: NSNotification) {

    let textField = notification.object as! UITextField
    print(textField.text!)

}

Swift 3版本

yourTextField.addTarget(self, action: #selector(YourControllerName.textChanges(_:)), for: UIControlEvents.editingChanged)

把零钱放在这里

func textChanges(_ textField: UITextField) {
    let text = textField.text! // your desired text here
    // Now do whatever you want.
}

希望能有所帮助。


Swift 4版本

使用键值观察 通知对象对其他对象属性的更改。

var textFieldObserver: NSKeyValueObservation?

textFieldObserver = yourTextField.observe(\.text, options: [.new, .old]) { [weak self] (object, changeValue) in
  guard let strongSelf = self else { return }
  print(changeValue)
}

KVO解决方案不起作用

KVO不工作在iOS控件:http://stackoverflow.com/a/6352525/1402846 https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/KVO.html

在观察课上,你要这样做:

假设你知道你想要观看的文本视图:

var watchedTextView: UITextView!

这样做:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(changed),
    name: UITextView.textDidChangeNotification,
    object: watchedTextView)

但是,要注意:

很可能你只想调用它一次,所以不要在layoutSubviews中调用它 在抚养孩子的过程中,很难知道什么时候最好。这取决于你的情况。不幸的是,没有标准的、固定的解决方案 例如,你通常肯定不能在初始化时调用它,因为当然watchedTextView可能还不存在

.

下一个问题是……

当以编程方式更改文本时,不会调用任何通知。

这是iOS工程中一个巨大的、古老的、愚蠢的麻烦。

当.text属性以编程方式更改时,控件根本不会调用通知。

这是非常烦人的,因为每个应用程序都以编程方式设置文本,比如在用户发布后清除字段,等等。

你必须像这样子类化文本视图(或类似的控件):

class NonIdioticTextView: UIITextView {

    override var text: String! {
        // boilerplate code needed to make watchers work properly:
        get {
            return super.text
        }
        set {
            super.text = newValue
            NotificationCenter.default.post(
                name: UITextView.textDidChangeNotification,
                object: self)
        }

    }

}

(提示-不要忘记超级电话必须在之前到来!邮政电话。)

没有可用的解决方案,除非您通过上面所示的子类化来修复控件。这是唯一的解决方案。

注意,通知

UITextView.textDidChangeNotification

结果

func textViewDidChangeSelection(_ textView: UITextView) 

被称为。

(不是textViewDidChange。)


一个是你可能有多个uitextfield。所以,给他们一个标签,然后你可以打开标签。下面是如何在任何类中设置一个观察者。

private func setupTextFieldNotification() {
    NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: nil, queue: OperationQueue.main) { (notification) in
        if let textField = notification.object as? UITextField, textField.tag == 100, let text = textField.text {
            print(#line, text)
        }
    }
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

迅捷用户界面

如果你正在使用原生的SwiftUI TextField或只是使用UIKit UITextField(这里是如何),你可以观察文本的变化,如:

SwiftUI 2.0

从iOS 14, macOS 11,或任何其他包含SwiftUI 2.0的操作系统中,有一个名为.onChange的新修饰符,用于检测给定状态的任何变化:

struct ContentView: View {
    @State var text: String = ""

    var body: some View {
        TextField("Enter text here", text: $text)
            .onChange(of: text) {
                print($0) // You can do anything due to the change here.
                // self.autocomplete($0) // like this
            }
    }
}

SwiftUI 1.0

对于旧的iOS和其他SwiftUI 1.0平台,你可以在combine框架的帮助下使用onReceive:

import Combine
.onReceive(Just(text)) { 
    print($0)
}

注意,您可以使用文本。publisher而不是Just(text),但它返回的是更改的值而不是整个值。


从iOS 14开始,不需要创建选择器,你可以通过一个闭包来传递一个UIAction:

let editingChanged = UIAction { _ in
    // Do something when text changes...
}
myTextField.addAction(editingChanged, for: .editingChanged)