kyurkchyan
kyurkchyan

Reputation: 2428

UITextField delegate methods are not fired when setting text programmatically

I've created a custom input view for entering text into UITextField. Basically it's just custom designed number pad. I have textfields, on which I've set the inputView property to use my custom created UIView subclass. In that view I have collection of buttons - from 0-9 and also backspace.

Now I want to change the text of UITextField programmatically when those buttons are tapped. The UITextField adopts UITextInput protocol, which in it's turn adopts UIKeyInput protocol. In that protocol I have all the methods I need, i.e. inserting text into cursor position and deleting text.

The problem is that those methods do not fire UITextField delegate methods. That is if I have custom validation in textField:shouldChangeCharactersInRange:replacementString: field for instance, that won't work. I've tried to set the text property of UITextField directly, but that didn't work also.

What is the right way of inserting text into UITextField, I mean insert text in a way that all delegate methods would be called?

Upvotes: 22

Views: 7574

Answers (3)

David Lindsay
David Lindsay

Reputation: 220

Set the text of UITextField by calling insertText:

aTextField.insertText(" ")

Upvotes: 9

Kris Coleman
Kris Coleman

Reputation: 426

I tried using textField:shouldChangeCharactersInRange:replacementString:without luck. I kept encountering a "bad selector sent to instance" crash when I tried invoking that method.

I also tried raising the Editing events, but I still never reached my breakpoint in my ShouldChangeText override of my UITextFieldDelegate.

I decided to create a helper method which would either invoke the text field's delegate (if exists) or the virtual ShouldChangeCharacters method; and based on that returning true or false, will then change the Text.

I'm using Xamarin.iOS, so my project is in C#, but the logic below could easily be re-written in Objective-C or Swift.

Can be invoked like:

    var replacementText = MyTextField.Text + " some more text";
MyTextField.ValidateAndSetTextProgramatically(replacementText);

Extension Helper Class:

/// <summary>
/// A place for UITextField Extensions and helper methods. 
/// </summary>
public static class UITextFieldExtensions
{
    /// <summary>
    /// Sets the text programatically but still validates
    /// When setting the text property of a text field programatically (in code), it bypasses all of the Editing events. 
    /// Set the text with this to use the built-in validation.
    /// </summary>
    /// <param name="textField">The textField you are Setting/Validating</param>
    /// <param name="replacementText">The replacement text you are attempting to input. If your current Text is "Cat" and you entered "s", your replacement text should be "Cats"</param>
    /// <returns></returns>
    public static bool ValidateAndSetTextProgramatically(this UITextField textField, string replacementText)
    {
        // check for existing delegate first. Delegate should override UITextField virtuals
        // if delegate is not found, safe to use UITextField virtual
        var shouldChangeText = textField.Delegate?.ShouldChangeCharacters(textField, new NSRange(0, textField.Text.Length), replacementText)
                               ?? textField.ShouldChangeCharacters(textField, new NSRange(0, textField.Text.Length), replacementText);
        if (!shouldChangeText)
            return false;

        //safe to update if we've reached this far
        textField.Text = replacementText;
        return true;
    }
}

Upvotes: 1

Niketan Patel
Niketan Patel

Reputation: 11

self.textfield.delegate = self;
    [self.textfield addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

/* Put Your View controller Object instead self when delegate methods are in another class */

/* textfield delagete called when text did view change */

-(void)textFieldDidChange:(UITextField *)textView
{
    if(Condition You want to put)
    {
        //Code
    }
    else
    {
        //Code
    }
}

As par this method you want to make custom Methods too.

Upvotes: 0

Related Questions