Calling textField:shouldReplaceCharactersInRange from a delegate method - ios

I've built a custom on-screen keyboard where each key tap returns a String?. In my delegate method, I want to forward that text onto the UITextFieldDelegate method: func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
func valueWasSent(string: String?) {
// activeTextField is a UITextField?
guard let textField = activeTextField else { return }
let range = NSMakeRange(0, string!.count - 1)
textField(activeTextField!, shouldChangeCharactersIn: range, replacementString: string!)
}
The last line here isn't working, and throwing the error:
Cannot call value of non-function type 'UITextField'
Any idea how I can accomplish this? Thanks

Most likely you should not be calling that delegate method yourself. The shouldChangeCharactersIn is simply a check if the edit would be valid. Normally, UITextField calls it to ensure the proposed change will be valid or not. If not, the change is ignored. If so, then the text field's text is updated.
If you really do want to call it, then you need to call it on the delegate, not self. You need to check the return value. If it returns true then you should update the text field's text accordingly.
if textField.delegate?.textField(textField, shouldChangeCharactersIn: range, replacementString: string!) {
// update the text field's text
}
Also note that the range you pass to it should reflect the current selection in the text field. You are setting it to match the length of string. That's bad. If you want string to fully replace the current value, at least pass in a range that matches the current value of the text field, not of string.

Related

Why does returning false in shouldChangeCharactersIn override old text in UITextField?

Problem Code
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return false
}
TextField Creation
#discardableResult fileprivate func otpTextField() -> BJOTPTextField {
let textField = BJOTPTextField()
textField.text = "1"
textField.delegate = self
textField.textColor = .black
textField.textAlignment = .center
textField.isSecureTextEntry = true
textField.keyboardType = .numberPad
return textField
}
Question
I have a UITextField subclass in my view controller which has text ("1") at the time of initialising. I copy-paste a large text onto the textfield. In shouldChangeCharactersIn method, even though I return explicitly false, the current text ("1") in the textfield gets removed, and becomes empty, why?
shouldChangeCharactersIn documentation
Returns true if the specified text range should be replaced;
otherwise, false to keep the old text.
Why is my old text not maintained? And an important observation is that the textfield override happens before shouldChangeCharactersIn is called. Very weird.
PS: The text of the textfield is not altered/assigned anywhere outside of shouldChangeCharactersIn method.
I got why this is happening. The reason is due to the textfield being a SecureTextEntry one.
The default behaviour in iOS for a password textfield is that, when you have already typed something in the (password) textfield, if it again becomes the first responder (by resigning its first responder status earlier), and you paste or start typing something, the existing contents will be cleared. This happens to allow the user to type in the correct password assuming that the previous entry was incorrect.
This serves to be a good user experience, but this overriding/emptying is not reflected/broadcast anywhere in the shouldChangeCharactersIn delegate method. In fact, the delegate method gets called only after the text overriding happens.
There is no problem and everything works fine as expected if it is not a secure textfield.

iOS, Swift, UITextField Changing Colour of Text being typed using typingAttributes, first letter's colour is not changed

I'm trying to change the colour of text being typed to white in UITextfield. I've used following code, which works but it doesn't change the colour of first letter to white. See the attached screenshot.
How to make it work so that colour of first letter also changes to white?
I've searched a lot but couldn't find the solution.
Tx in advance!
#IBAction func emailFieldEditingChanged(_ sender: UITextField) {
emailTextField.typingAttributes![NSAttributedStringKey.foregroundColor.rawValue] = UIColor.white
}
You'll want to set the delegate as Rakesha mentioned, but you have to change it each time the user inputs a character. Use this delegate method.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
emailTextField.typingAttributes![NSAttributedStringKey.foregroundColor.rawValue] = UIColor.white
return true
}
//Set this in viewDidLoad, and don't forget to include the delegate.
emailTextField.delegate = self

TextField and Warning

I have a UITextField object and take input from the textfield. If length of the input is shorter than 2, I want to give warning sign in the textfield bar.
Is this impossible ?
If it is so, how can I handle that ?
EDIT:
I just handled it. I put a label in the textfield and run auto layout. Then, I chose delegate of textfield and make InputViewController conform to UITextFieldDelegate protocol. Finally, I use func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
Implement UITextFieldDelegate in your view controller and use textFieldDidEndEditing to check text length.
func textFieldDidEndEditing(_ textField: UITextField) {
if let textFieldText = textField.text {
print("textFieldText length - \(textFieldText.count)")
if (textFieldText.count < 2) {
showWarning(message: "Your message here")
}
}
}
func showWarning(message: String?){
// show warning message using UIAlertController here.
}
You can use a custom class inherited from UIView and pack UITextField(No border style) and Iconic Font UILabel inside it.

call prepareforsegue after user finished editing uitextfield

How do i pass the value of the text from the UITextField into another view controller. Currently, when I override the func prepareForSegue(), it is being called before the user finished editing the textfield, so the value passed is always null.
You have a couple of ways to go about this:
Directly access the text value of your TextField instead of your model, which sounds like it is updated after didFinishEditing
Instead of updating your model only on didFinishEditing you can update it every time the text changes by implementing internal func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool, and getting the new value with let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)

Swift: Disable or Clear Undo for a TextField

When selecting NumberPad for a TextField, the iPad displays a full keyboard, so I have created a function to simply remove all characters that are not numeric. However, if a Non-numeric key is pressed and then the user presses Undo on the keyboard, the App Crashes.
How do I disable the Undo function for the TextField or at least clear the Undo Stack?
The answer was simple in the end, I used undoManager removeAllActions, but instead of just needing:
undoManager?.removeAllActions()
as a line, I needed:
myTextField.undoManager?.removeAllActions()
I placed this in the DidChange Action for the TextField.
Add UITextFieldDelegate in your controller.
In your viewDidLoad() assign yourTextField.delegate = self. Than implement this method
public func textFieldShouldClear(textField: UITextField) -> Bool{
return false // This will disable clear button
}
Also for replacing text I would suggest use
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool{//Your Logic Here
}

Resources