UITextField文本更改事件

时间:2011-08-10 12:09:42

标签: ios objective-c swift event-handling uitextfielddelegate

如何检测textField中的任何文本更改?委托方法shouldChangeCharactersInRange适用于某些事情,但它并不能完全满足我的需要。由于它返回YES,因此textField文本不可用于其他观察者方法。

e.g。在我的代码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;
}

23 个答案:

答案 0 :(得分:984)

来自proper way to do uitextfield text change call back

  

我捕获发送到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 作为selector

答案 1 :(得分:364)

XenElement的答案很明显。

通过右键单击UITextField并将“Editing Changed”发送事件拖到子类单元,也可以在界面构建器中完成上述操作。

UITextField Change Event

答案 2 :(得分:124)

设置事件监听器:

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

实际听:

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

答案 3 :(得分:74)

<强>夫特:

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

然后,实现回调函数:

@objc func textFieldDidChange(textField: UITextField){

print("Text changed")

}

答案 4 :(得分:28)

如上所述:UITextField text change event,似乎从iOS 6 (已检查iOS 6.0和6.1),无法完全检测UITextField对象中的更改通过观察UITextFieldTextDidChangeNotification

现在似乎只跟踪由内置iOS键盘直接进行的更改。这意味着,如果您只是通过调用类似这样的内容来更改UITextField对象:myUITextField.text = @"any_text",则根本不会通知您任何更改。

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

我的“解决方案”是实际发布我自己对UITextField所做的每项更改的通知(如果在不使用内置iOS键盘的情况下完成更改)。像这样:

myUITextField.text = @"I'm_updating_my_UITextField_directly_in_code";

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

[NSNotificationCenter.defaultCenter 
  postNotification:myTextFieldUpdateNotification];

通过这种方式,您可以100%确信在更改.text对象的UITextField属性时会收到相同的通知,无论是在代码中“手动”更新它还是通过内置的iOS键盘。

重要的是要考虑到,由于这不是记录在案的行为,因此这种方法可能会导致收到2个UITextField对象中相同更改的通知。根据您的需求(UITextField.text更改时您实际执行的操作),这可能会给您带来不便。

如果您确实需要知道通知是您的还是“iOS制作”,那么稍微不同的方法是发布自定义通知(例如,使用UITextFieldTextDidChangeNotification以外的自定义名称)。

修改

我刚刚找到了一种不同的方法,我觉得可能会更好:

这涉及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”属性不会随时更新键入/删除新字母。相反,在您重新调整文本字段的第一个响应者状态后,文本字段对象将“作为一个整体”更新。

答案 5 :(得分:23)

我们可以轻松地从Storyboard配置,CTRL拖动@IBAction并更改事件如下:

enter image description here

答案 6 :(得分:13)

这里有swift版本。

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

func textFieldDidChange(textField: UITextField) {

}

由于

答案 7 :(得分:10)

我解决了改变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
}

答案 8 :(得分:10)

Swift Version tested:

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

Parameters explained:

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

Then add the method you created above in your UIViewController:

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

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

}

答案 9 :(得分:5)

对于Swift 3.0:

let textField = UITextField()

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

使用类:

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

    }
}

答案 10 :(得分:5)

Swift 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!)

}

答案 11 :(得分:3)

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.
}

希望它有所帮助。

答案 12 :(得分:2)

你应该使用通知来解决这个问题,因为另一种方法会监听输入框而不是实际输入,特别是当你使用中文输入法时。 在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;
} 

}

最后,你跑,将完成。

答案 13 :(得分:2)

Swift 3.1:

  

Selector:ClassName.MethodName

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

  func fieldChanged(textfieldChange: UITextField){

    }

答案 14 :(得分:2)

关闭:

   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
 }

答案 15 :(得分:2)

  1. KVO解决方案 不起作用

KVO在iOS中不适用于以下控件:http://stackoverflow.com/a/6352525/1402846 https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/KVO.html

  1. 在观察课中,您需要这样做:

鉴于您知道要观看的文本视图:

var watchedTextView: UITextView!

执行此操作:

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

但是,请注意以下事项:

  • 您很可能只想打一次 ,所以不要用layoutSubviews

    < / li>
  • 在启动过程中很难知道何时最好调用它。这将取决于您的情况。 不幸的是,没有标准的锁定解决方案

  • 例如,您通常可以在init时间 调用它,因为当然watchedTextView可能还不存在< / p>

  1. 下一个问题是...
以编程方式更改文本时,

没有通知会被调用。

这是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。)

答案 16 :(得分:1)

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

   }

}

不要忘记设置代理。

答案 17 :(得分:1)

** (MatchError) no match of right hand side value: <<41, 0, 0, 84, 0, 0, 0, 0, 208, 115, 213, 0, 249, 20, 0, 0, 76, 73, 70, 88, 86, 50, 0, 0, 196, 240, 247, 239, 158, 36, 38, 20, 3, 0, 0, 0, 1, 124, 221, 0, 0>>

答案 18 :(得分:1)

从 iOS 14 开始不需要创建选择器,你可以传递一个带有闭包的 UIAction

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

答案 19 :(得分:0)

Swift 4 Version

Using Key-Value Observing Notify objects about changes to the properties of other objects.

var textFieldObserver: NSKeyValueObservation?

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

答案 20 :(得分:0)

一件事是您可能有多个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)
}

答案 21 :(得分:0)

SwiftUI

如果您正在使用本机SwiftUI TextField或仅使用UIKit UITextField here is how ),则可以观察到文本更改,例如:

SwiftUI 2.0

从iOS 14,macOS 11或任何其他包含SwiftUI 2.0的操作系统开始,有一个名为.onChange的新修饰符,用于检测给定state的任何更改:

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

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

答案 22 :(得分:-1)

使用观察者和反应式Swift(RxCocoa&RxSwift)真的很简单。

只需订阅rx的text属性,如下所示:

myTextField.rx.text.subscribe { text in
   print("UITextFieldTextChangeEvent Text:\(text)")
}.disposed(by: disposeBag)