UITextField delegate methods are not fired when setting text programmatically - ios

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?

Set the text of UITextField by calling insertText:
aTextField.insertText(" ")

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

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.

Related

How to unclear UITextField secure text entry in Swift?

When I use default Security text Entry in UITextField in Swift Language after type type text once UITextField.
Once loss focus from UITextField after try to edit Secure text then UITextField is first reset and after it start put new text in UITextField.
How to edit old Secure Text without Storing data into Any Kind of String object
I'd suggest to create a custom UITextField class and override become​First​Responder() method do add your desired functionality:
You can override this method in your custom responders to update your
object's state or perform some action such as highlighting the
selection. If you override this method, you must call super at some
point in your implementation.
The custom Class should be similar to:
class CustomSecureTextField: UITextField {
override func becomeFirstResponder() -> Bool {
super.becomeFirstResponder()
if !isSecureTextEntry { return true }
if let currentText = text { insertText(currentText) }
return true
}
}
The logic of the implementation of becomeFirstResponder as follows:
By default, the secured-entry text field clears the inserted text when it is become first responder text, so what's happening in CustomSecureTextField that if the text field is secured-entry, it will re-insert the current inserted text -after clearing it-, but you have to make sure that the text field input is secured (that's the purpose of adding if !isSecureTextEntry { return true }) or the text will be duplicated (re-inserted) each time the text field becomes first responder.
Output:
Note that both of text fields are types of CustomSecureTextField:
This answer helped me to figure out this problem.
textField.isSecureTextEntry = true
following property not gonna work if you make testField isSecureTextEntrysecure property makes true .
textField.clearsOnBeginEditing = false
There is an issue with the #Ahmd F solution when you simply tap on the field it will automatically add the text to the field I have resolved that in the below code thanks
override open func becomeFirstResponder() -> Bool {
super.becomeFirstResponder()
if !isSecureTextEntry { return true}
if let currrentText = text {
self.text = ""
insertText(currrentText)
}
return true
}

Append text to a UITextField with custom keyboard made out of buttons

I have a static numeric-keyboard made out of a bunch of buttons, I also have three UITextFields, textField1, textField2 and textField3 where I'm inputting the text using the static keyboard.
Here is the code I'm using to detect which textField is currently in focus and to input the content of the buttons. It kind of works but I don't like the fact that I have three IF statements and I'm not sure how to prevent the keyboard from appearing when a textField is tapped.
What would be the best way to implement this functionality?
#IBAction func appendKey(sender: AnyObject) {
let digit = sender.currentTitle!
if(textField1.isFirstResponder()){
textField1.text = textField1.text! + digit!
}else if(textField2.isFirstResponder()){
textField2.text = textField2.text! + digit!
}else if(textField3.isFirstResponder()){
textField3.text = textField3.text! + digit!
}
}
Thanks
If the standard keyboard is displaying then your custom keyboard isn't setup properly. Your custom keyboard should be the inputView of each UITextField. If you do that, the standard keyboard won't appear and yours will instead.
Your custom keyboard should be a separate class that handles all of it's own buttons. It appears you have everything in one view controller - all of the text fields, all of the buttons, and all of the button handling code. This is a bad approach. Create your custom keyboard class view. Put all of the code to handle and display the buttons in that custom view class. Create a single instance of this view in your view controller and assign the custom keyboard view instance to the inputView property of each text field.
In the custom keyboard class, listen for the UITextFieldTextDidBeginEditingNotification notification. This is how you keep track of the current text field. Your custom keyboard class should not have any specific reference to any text field other than track the current one. It should also ensure that the text field's inputView is itself.
In each button handler of the custom keyboard class, get the text you wish to append and then call the text field's insertText: method with the string. That's it. This will ensure the text is inserted and/or replaced based on the current selecting in the text field.

How to change UITextView Hyperlink selection background color?

I am using a UITextView to make hashtags selectable. It detects taps perfectly. My issue is with the selection color. It looks black and I wanted the text to fade a bit on selection instead.
Here's what I've got now:
I've tried changing the tintColor, the NSForegroundColorAttributeName, and the NSBackgroundColorAttributeName but it doesn't work.
There is no documented property for the selected or highlighted color of detected links, but you should be able to achieve the same effect by overriding the delegate method textView:shouldInteractWithURL:inRange: and changing the color yourself.
From the UITextViewDelegate protocol reference:
The text view calls this method if the user taps or long-presses the
URL link. Implementation of this method is optional. By default, the
text view opens the application responsible for handling the URL type
and passes it the URL. You can use this method to trigger an
alternative action, such as displaying the web content at the URL in a
web view within the current application.
The last parameter is an NSRange object called characterRange, which represents the character range containing the tapped URL (or hashtag). Using that range, you should be able to add attributes such as NSForegroundColorAttributeName so as to change only the color of the particular hashtag that was tapped.
You'll probably want to revert any changes on touchesEnded and touchesCancelled.
Alternatively, you could make your own subclass and manually handle the above.
Although there is no public API to do this, I was curious and decided to dig through the private header for UITextField. I found that there is a class method on UITextField _sharedHighlightView which returns an instance of the private _UIHighlightView class. This is the class in charge of the highlighting. Swizzling _sharedHighlightView and changing its color will allow you to change the color of any data-detected links:
WARNING: This is a hack that uses method swizzling and private APIs/properties.
class MyTextView: UITextView {
var newHighlightView: AnyObject?
func changeHighlight() {
self.newHighlightView = UITextView.performSelector(Selector("_sharedHighlightView")).takeUnretainedValue()
self.newHighlightView?.setValue(UIColor.redColor().colorWithAlphaComponent(0.6), forKey: "_color")
let originalHighlightView = class_getClassMethod(MyTextView.self, Selector("_sharedHighlightView"))
let newHighlightView = class_getClassMethod(MyTextView.self, #selector(MyTextView.swizzleHighlightView))
method_exchangeImplementations(originalHighlightView, newHighlightView)
}
func swizzleHighlightView() -> AnyObject {
return self.newHighlightView!
}
}
In your View Controller:
let textView = MyTextView(frame: CGRect(x: 0, y: 40.0, width: 200.0, height: 200.0))
textView.dataDetectorTypes = .All
textView.editable = false
textView.text = "Some text. http://www.google.com/"
textView.changeHighlight()
self.view.addSubview(textView)
Result:
This could probably be cleaned up a little further by not force-unwrapping any optionals.
Work around for this can be done, you can use UIButton instead of textview. By using button you can have the same effect.

dynamically change UIKeyboards return key

I have two UITextfield the user enters his name into the first and email into the second. I would like to know how to change the UIKeyboards return key depending if the name text field has an entry or not.
For instance if nametextfield is empty then I would like the UIkeyboard return key to be Next
else if the nametextfield has an entry in it then when the user selects the email text field I would like the return key to be submit.
Is this possible? if so how would I go about accomplishing it? any help would be appreciated.
You can have return key customized to prefixed values that you can see in UIReturnKeyType enum for each UITextField.
textFieldName.returnKeyType = UIReturnKeyNext;
textFieldEmail.returnKeyType = UIReturnKeyDefault;
Not sure if this is what you're looking for though.
You have a chance to set up keyboard characteristics in the UITextFieldDelegate Protocol method textFieldShouldBeginEditing: which is called before the text field becomes the first responder (indeed to decide if it may become the first responder). If you don't already have a delegate for the text field(s) in question you would have to assign one and implement at least that method. Presumably the same object handling the text field could hold the delegate methods. The following implementation sets the return key to "Search".
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"textFieldShouldBeginEditing");
textField.returnKeyType = UIReturnKeySearch;
return YES;
}
You'd have to look at the contents of your text fields to decide what value to use.
Make use of the textField.returnKeyType property.
you can check out all the available options here http://developer.apple.com/library/ios/documentation/uikit/reference/UITextInputTraits_Protocol/Reference/UITextInputTraits.html#//apple_ref/doc/c_ref/UIReturnKeyType
textfield.returnKeyType = UIReturnKeySearch;

iPhone/iPad: How to make UITextField readonly (but not disabled)?

I understand this question has been asked before, but I'm not satisfied with the answers, i.e. by making it disabled. There is a fundamental difference: Disabled view doesn't fire events, but for a read-only view, it should still fire event like (e.g. TouchUpInside), and I need it. Only thing I don't want is the keyboard input.
The reason is that I have several input fields, some can useUITextField directly, others are not. I want to have them look similar. So, I'd like to use UITextField to display all of them. Some of them need to be read-only so that I can use touch up event for alternative input.
Or there might be a completely different way to do it?
EDIT: This is for my MonoTouch project. I have very limited knowledge of Objective-c.
Say you have 2 text field instance variables connected to text fields you created in the Interface Builder. Lets call them myReadOnlyTextField and myEditableTextField. Make sure you connect the delegate property of each text field in the Interface Builder to the view controller ("File's Owner")[1]. Now, in the view controller #implementation (.m file), use the method textFieldShouldBeginEditing: and put in some logic to determine which text field you want to allow editing and which to not allow editing; something like this:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
BOOL editable;
if (textField == myReadOnlyTextField) {
editable = NO;
} else if (textField == myEditableTextField) {
editable = YES;
} else {
// editable = YES/NO/Other Logic
}
return editable;
}
From the UITextFieldDelegate Documentation:
textFieldShouldBeginEditing:
Asks the delegate if editing should begin
in the specified text field.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
Parameters
textField - The text field for which editing is about to
begin.
Return Value
YES if an editing session should be initiated;
otherwise, NO to disallow editing.
Discussion
When the user performs an action that would normally
initiate an editing session, the text field calls this method first to
see if editing should actually proceed. In most circumstances, you
would simply return YES from this method to allow editing to proceed.
Implementation of this method by the delegate is optional. If it is
not present, editing proceeds as if this method had returned YES.
UITextField Documentation is a good read also.
[1] You can do this programmatically as well. Here is an example:
- (void)viewDidLoad {
[super viewDidLoad];
// .....
myReadOnlyTextField.delegate = self;
myEditableTextField.delegate = self;
}
Despite the fact you need no keyboard, textField:shouldChangeCharactersInRange:replacementString: is very useful. It prevents text field from editing but still leaves it selectable in contrast to textFieldShouldBeginEditing:.
In monotouch:
var txt = new UITextField();
txt.ShouldChangeCharacters += (field, range, replacementString) => false;
You can have two options:
a) to use ShouldBeginEditing with return false, but you can't use PickerView as InputView in your text field.
b) to use ShouldChangeCharacters that will prevent the editing but will allow to use InputView with PickerView.
Objective C:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
return NO;
}
Swift :
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return false
}
because you are working in MonoTouch you could use the following line of code:
myReadOnlyButton.ShouldBeginEditing = t =>
{
//event code
return false;
};
I personally use borderStyle = .none + userInteractionEnabled = false to make it look like a regular label.

Resources