RxSwift Control Event with UITextFieldDelegate - ios

I am using RxSwift for a project. I am using the control events to handle the textfield events such as follows.
textField.rx.controlEvent([.editingDidEndOnExit]).subscribe { _ in }.disposed(by: disposeBag)
Now I need to handle a delegate method
textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
If I add the delegate to the textField, the controlEvents stop working.
Does anybody have a suggestion about how can I handle this case where I can use both the control events and delegate methods?
Or should I just remove either of these handling.
Thanks.

The editingDidEndOnExit control event stops working because the delegate is changing the behavior of the return key. Add a textFieldShouldReturn(_:) to your delegate and have it return true, then the controlEvent will work as expected.
extension ExampleViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// can only enter numbers with this. An example of the sort of thing you
// might want to put in this method.
return string.isEmpty || string.allSatisfy { !$0.unicodeScalars.contains { !NSCharacterSet.decimalDigits.contains($0) } }
}
// this method must exist. If you don't add a delegate to your text field,
// the default behavior is as if this returned true. If you add a delegate,
// then the field's default behavior changes to false and you have to
// implement this method to get it to return true again.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return true
}
}

Related

In a Swift UITextFieldDelegate how to trigger an action when the text is edited?

I have a ViewController which inherits from UITextFieldDelegate and serves as the delegate for the text field in the view. I would like to trigger an action whenever the text is edited.
I tried implementing the textField method, which is listed in the UITextFieldDelegate documentation:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
The documentation describes this textField method as triggered when the text should be changed, which occurs before the specified text is changed. Here is the line from the documentation:
Asks the delegate if the specified text should be changed.
As this textField method triggers before the text is changed rather than after, the text available at textField.text therefore contains the prior text, not the new text updated after the change. To access the new text, I would need to apply the range and replacementString parameters to textField.text to imitate how the text will be changed.
Is there an alternative to the textField method that is triggered not when the text will be changed, but instead when the text has been changed? I'm thinking that directly using the text after the change would prevent me from having to hack an imitation of the change beforehand.
Add a target with a selector for valueChanged and you'll be able to get the events like you need here.
// adding target
textField.addTarget(self, action: #selector(textChanged), for: .valueChanged)
// selector
#objc func textChanged(_ textField: UITextField) {
print(textField.text)
}
Have you tried textDidChangeNotification? you will have to add observer for keyboarddidshow(notification).
For ur Ref:
https://stackoverflow.com/a/52325593
Just write extension UITextfieldDelegate to viewController, you will have these pre-defined functions:
func textFieldDidBeginEditing(_ textField: UITextField) {
}
func textFieldDidEndEditing(_ textField: UITextField) {
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
}

Swift prevent "0" being first character for 1 specific uiTextField

so i search online about how "func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool" for formating textField. i found this way to prevent "0" as my first char in my textfield. it works but, actually not the way i wanted.
The thing is, in my register view theres 4 uiTextfield, which contain :
Name
Phone Number
Pin
Confirm Pin
i only want to prevent "0" as my first char only for my PhoneNum TextField. but with this code, i kinda put all of those 4 textField into prevent "0" as the first char.
here's my code :
#IBOutlet weak var textFullName: SkyFloatingLabelTextField!
#IBOutlet weak var textPhoneNumber: SkyFloatingLabelTextField!
#IBOutlet weak var textPIN: SkyFloatingLabelTextField!
#IBOutlet weak var textConfirmPIN: SkyFloatingLabelTextField!
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// I try this one
if string == "0" {
if textField.text!.count == 0 {
return false
}
}
// i also try to change the "textField" into "textPhoneNumber"
if string == "0" {
if textPhoneNumber.text!.count == 0 {
return false
}
}
// both of those method wont work
return true
}
can someone tell me how to just prevent my textPhoneNumber to cannot type "0" as its first char? with this method i only put all of my textfield into cannot type "0" as its first char.
Thanks guys
The UITextFieldDelegate methods will get called for ALL of the text fields for which the view controller is set up as the delegate.
Presumably your textField(_:shouldChangeCharactersIn:replacementString:) method is being called for all 4 of your SkyFloatingLabelTextField objects (which I assume are a custom subclass of UITextField.)
If you want different behavior for different text fields, you need to write your code to handle each case separately. Something like this:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
switch textField {
case textPhoneNumber:
//Special case code to handle the phone number field
if string == "0" {
if textField.text!.count == 0 {
return false
}
return true
}
case textFullName:
//Special case code to handle the name field (if needed.)
default:
//Shared code to handle the other fields the same way
}
}
You can check if the textField is textPhoneNumber directly by using the equatability == sign.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == textPhoneNumber {
// do textPhoneNumber stuff
} else {
// others
}
return true
}

Password AutoFill in iOS 11 ignores NO returned from textField:shouldChangeCharactersInRange:replacementString:

My iOS app has username & password text fields. The username has specific limitations which are ensured by textField:shouldChangeCharactersInRange:replacementString: which returns NO for invalid resulting strings.
In iOS 11 I observe an issue when 'Password AutoFill' feature is used. In this case delegate method is called, but its result is ignored and text is replaced in any case regardless of returned value.
Is it by design, or bug, or maybe I'm missing something?
Yes it is by design, when you set the text property of an textfield, the delegate method below is not called, that's what it might happen
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
Neither this method below does help anyhow
func textFieldDidEndEditing(_ textField: UITextField) -> Bool {
return true
}
But you could subclass UITextfield, override text property create an extension for the UITextFieldDelegate with a default method 'textChanged' and implement the 'textChanged' method in the delegate
extension UITextFieldDelegate{
func textChanged(_ textField:UITextField){
print("textChanged")
}
}
class CustomTF: UITextField {
override var text: String?{
didSet{
print("didSet text")
delegate?.textChanged(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.

what function can help me to know user input first character in textfield and how to make a blank line when I press keyboard return?

I have two problems.I am a beginner of swift
First,I want to hide the send button until user input frist character.I use textfield delegate functions that they don't implement this idea.
And then, I want to creat a blank line when user input in textfield.I know to use "textFieldShouldReturn" function ,but I use "\n" that it doesn't work for me.How to do this?
this is my code:
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField.text?.isEmpty == false {
aButton.isHidden = true
sendButton.isHidden = false
}
}
update code:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.textField.text = "\n"
return true
}
I also want the textfield change it height.let user can input their message. Does it can be implement?
Or I need to change textfield to textview.
You can use textfields delegate method to check when user start writing something in your textfield.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
if textField == txtUserName //compare with your textfield object which you have taken by outlet
{
if string.characters.count >= 1 {
//make your button enable
}else
{
// disable your button
}
}
return true
}

Resources