Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 881
kyurkchyan Avatar asked Jul 15 '14 08:07

kyurkchyan


2 Answers

Set the text of UITextField by calling insertText:

aTextField.insertText(" ")
like image 184
David Lindsay Avatar answered Nov 02 '22 20:11

David Lindsay


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;
    }
}
like image 1
Kris Coleman Avatar answered Nov 02 '22 20:11

Kris Coleman