I have 2 text fields on 2 different VC's.
The intended behaviour is for the text fields to become first responder (automatically load the keyboard without needing to tap) at the point the page loads.
When the user presses 'done' on the keypad, it should resign the responder and dismiss the keypad.
For some reason, when I add the code to allow the 'done' button to resign the first responder, it seems to be preventing the field becoming first responder when the page is loaded.
On VC1, I have :
//set the text field as first responder to auto open keyboard
override func viewDidAppear(_ animated: Bool) {
authorNameOutlet.becomeFirstResponder()
}
and then
//make the done button on the keypad dismiss the keyboard
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
authorNameOutlet.resignFirstResponder()
return true
}
This page does not auto open the keypad and set first responder on page load.
On my 2nd VC, I've removed the textFieldShouldReturn method and the first responder works perfectly, auto opening the keypad on the textfield with tapping. However, in this case the 'done' button now does nothing because the 'textFieldShouldReturn' isn't there.
I can't see what I'm doing wrong, the way I see it I'm setting my first responder in the right place (viewDidAppear) and the responder should only resign once done is pressed?
I also have some validation but don't think that's relevant :
//disable button if not all fields completed when finished editing
func textFieldDidEndEditing(_ textField: UITextField) {
if titleOutlet.text?.isEmpty == false {
confirmButtonOutlet.isEnabled = true
} else {
confirmButtonOutlet.isEnabled = false
}
}
I've looked at other answers but this is a pretty simple implementation and can't work out why it isn't working!
UPDATESo I just noticed that the page transitions slightly differently and remembered VC1 (where it isn't working) is part of a PageView Controller and the page where it IS working isn't (it's just segued from there but is a normal VC).
I also can confirm that adding the textFieldShouldReturn to the second VC doesn't make a difference so that's a red herring.
Is there any reason being part of a PVC would change the behaviour? Wonder if there's a different delegate to subscribe to in that VC?
UPDATE whole code for VC1 where is isn't working (NB. i've tried removing the page fade but that doesn't impact it and this is the same on the 2nd VC where it is working)
import UIKit
import RealmSwift
class OnboardingNameVC: UIViewController, UITextFieldDelegate {
@IBOutlet weak var authorNameOutlet: UITextField!
@IBOutlet weak var titleOutlet: UILabel!
@IBOutlet weak var confirmButtonOutlet: UIButton!
@IBAction func confirmNamePressed(_ sender: Any) {
addAuthorName()
}
override func viewDidLoad() {
super.viewDidLoad()
authorNameOutlet.attributedPlaceholder = NSAttributedString(string: "Joe Bloggs",
attributes: [NSAttributedStringKey.foregroundColor: UIColor.lightGray.withAlphaComponent(0.5)])
authorNameOutlet.delegate = self
confirmButtonOutlet.isEnabled = false
authorNameOutlet.setBottomBorder(withColor: UIColor.lightGray)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
authorNameOutlet.becomeFirstResponder()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
animateFade()
}
func addAuthorName() {
let realm = try! Realm()
let authorToCreate = AuthorPreferences()
authorToCreate.AuthorName = authorNameOutlet.text!
try! realm.write {
realm.add(authorToCreate)
performSegue(withIdentifier: "nameToTitleSegue", sender: self)
}
}
//disable button if not all fields completed when finished editing
func textFieldDidEndEditing(_ textField: UITextField) {
if authorNameOutlet.text?.isEmpty == false {
confirmButtonOutlet.isEnabled = true
} else {
confirmButtonOutlet.isEnabled = false
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
authorNameOutlet.resignFirstResponder()
return true
}
//animations
func animateFade() {
let labels : [UIView] = [titleOutlet, authorNameOutlet, confirmButtonOutlet]
var delay = 0.3
let duration = 1.2
for label in labels {
label.fadeIn(duration: duration, delay: delay)
delay += 0.2 // Increment delay
}
}
}
EDIT - SOLVED!
After realising the different page transition behaviour I realised that VC1 was part of a PageViewController.
As a result I needed to add this to the viewDidAppear :
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.async {
self.authorNameOutlet.becomeFirstResponder()
}
}
It now works fine.
TLDR: If you have a textField within a pageviewController and become first responder isn't working as normal you probably need to add to the dispatch queue as per above!