UITextField文本更改事件

kar*_*rim 546 objective-c event-handling ios uitextfielddelegate swift

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

例如,在我的代码calculateAndUpdateTextFields中没有获得更新的文本,用户已键入.

他们是否有办法获得类似textChangedJava事件处理程序的东西.

- (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;
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*son 1022

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

我捕获发送到UITextField控件的字符,如下所示:

// Add a "textFieldDidChange" notification method to the text field control.
Run Code Online (Sandbox Code Playgroud)

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

您可以使用它并将calculateAndUpdateTextFields作为您的textFieldDidChange.

  • 这是更好的解决方案 - 因为您也可以在Nibs或Storyboard中设置它,而且您不必写出过多的UITextFieldTextDidChangeNotification代码 (18认同)
  • 您可能会想到Apple的`UITextFieldDelegate`类似于`func textField:UITextField,didChangeText text:String`就会被包含在内,但......*(给Apple的人一个邋look的样子)* (9认同)
  • @iWheelBuy只有当它返回"NO"时才是合乎逻辑的,因为当你从这个方法返回"NO"时,你基本上是说字段中的文本不应该改变. (4认同)
  • 唯一的问题是.它对我不起作用 - (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string (3认同)
  • 这对于编辑引起的更改非常有用。它不会捕获通过以下方式发生的编程更改:`textField.text = "Some new value";`。有没有聪明的方法来捕捉这个? (2认同)

Wil*_* T. 377

XenElement的答案很明显.

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

UITextField更改事件

  • 可能很容易,但是经过 10-15 分钟的搜索,直到偶然发现您的答案,我才发现这种可能性。从我这里获得另一个+1;很高兴让基于代码和基于 IB 的解决方案都对这样的问题进行高度投票。 (2认同)
  • 为什么它的名字叫做编辑改变?狂!谢谢你的解决方案:-) (2认同)
  • 因为在编辑更改时调用事件,而在文本字段完成编辑时发生值更改,即辞职第一响应者.UITextFieldTextDidChangeNotification是一个UITextField通知,而UIControlEventValueChanged是由UIControl实现的,UIBontrol是UIButton的子类. (2认同)
  • 我注意到这不起作用,因为用户选项卡超出了文本字段,并且自动更正的文本替换了内容 (2认同)

小智 130

设置事件监听器:

[self.textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
Run Code Online (Sandbox Code Playgroud)

实际听:

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


Jua*_*ero 80

迅速:

yourTextfield.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: .editingChanged)
Run Code Online (Sandbox Code Playgroud)

然后,实现回调函数:

@objc func textFieldDidChange(textField: UITextField){

print("Text changed")

}
Run Code Online (Sandbox Code Playgroud)

  • 为我工作,我已经尝试过这个,但没有意识到该函数需要一个 textField 参数。如果这对您不起作用,请确保检查您的选择器是否具有要传入的 textField 的参数(即使您不使用它)。 (4认同)

小智 29

如上所述:UITextField文本更改事件,似乎从iOS 6(iOS 6.0和6.1已检查)开始,UITextField仅通过观察就无法完全检测对象中的更改UITextFieldTextDidChangeNotification.

现在似乎只跟踪由内置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];
Run Code Online (Sandbox Code Playgroud)

这样,当您更改对象的.text属性时UITextField,无论是在代码中"手动"更新还是通过内置的iOS键盘,您都可以100%确信收到相同的通知.

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

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

编辑:

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

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

基本上,您将自己注册为属性的观察者,如果此属性发生更改,您会收到有关它的通知."原则"非常类似于NSNotificationCenter工作方式,这种方法的主要优点是自动iOS 6(没有任何特殊调整,如必须手动发布通知).

对于我们的UITextField-scenario,如果您将此代码添加到例如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];

}
Run Code Online (Sandbox Code Playgroud)

相信有关"上下文"管理的答案:https://stackoverflow.com/a/12097161/2078512

注:好像当你在过程编辑UITextField与内置的iOS键盘,文本字段的"文本"属性不与每一个新的字母输入/删除更新.相反,在您重新调整文本字段的第一个响应者状态后,文本字段对象将"作为一个整体"更新.

  • 为什么要通过这个,只需使用XenElement答案中的target-action方法.如果你需要几十行代码做一些"应该"简单的事情,你可能做错了. (5认同)
  • 这似乎是预期的行为.没有其他委托方法(例如滚动,选择)被代码发起的事件调用. (5认同)

bik*_*ota 25

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

在此输入图像描述


Avi*_*oss 15

从 iOS 14 开始,无需创建选择器,您可以传递UIAction带有闭包的 a :

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


Hin*_*ndu 13

这里的swift版本相同.

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

func textFieldDidChange(textField: UITextField) {

}
Run Code Online (Sandbox Code Playgroud)

谢谢


Pau*_*uls 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
}
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案的问题是:Cursor位置设置为字段的END(只要执行textField.text = ...).因此,如果用户想要在字段中间编辑字符,那么每次按键时,它们的光标将转到字段的末尾.试试看吧. (3认同)

kem*_*ica 10

测试Swift版本:

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

参数说明:

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
Run Code Online (Sandbox Code Playgroud)

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

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

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

}
Run Code Online (Sandbox Code Playgroud)


hga*_*ale 6

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

}
Run Code Online (Sandbox Code Playgroud)


ped*_*uan 5

对于Swift 3.0:

let textField = UITextField()

textField.addTarget(
    nil,
    action: #selector(MyClass.textChanged(_:)),
    for: UIControlEvents.editingChanged
)
Run Code Online (Sandbox Code Playgroud)

使用类如:

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

    }
}
Run Code Online (Sandbox Code Playgroud)


Ria*_*man 5

Swift 3版本

yourTextField.addTarget(self, action: #selector(YourControllerName.textChanges(_:)), for: UIControlEvents.editingChanged)
Run Code Online (Sandbox Code Playgroud)

并在这里获取更改

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

希望能帮助到你。


Fat*_*tie 5

  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!
Run Code Online (Sandbox Code Playgroud)

做这个:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(changed),
    name: UITextView.textDidChangeNotification,
    object: watchedTextView)
Run Code Online (Sandbox Code Playgroud)

但是,请注意:

  • 您可能只想调用一次,因此不要调用它,例如,layoutSubviews

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

  • 例如,您通常肯定无法及时调用它init,因为当然watchedTextView可能还不存在

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

    }

}
Run Code Online (Sandbox Code Playgroud)

(提示 - 不要忘记 super 调用必须在post 调用之前进行!)

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

请注意,通知

UITextView.textDidChangeNotification
Run Code Online (Sandbox Code Playgroud)

结果是

func textViewDidChangeSelection(_ textView: UITextView) 
Run Code Online (Sandbox Code Playgroud)

被召唤。

不是 textViewDidChange。)