Set delegate for textField in ViewController that is owner of .xib - ios

I am trying to use an xib file to display a custom alter view. For that purpose i use the SimpleAlert from here. I have the .xib file with my textFields in it and as the owner of the .xib i set the ViewController is created.
import UIKit
class TestBaumViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tfFirst: UITextField!
#IBOutlet weak var tfSecond: UITextField!
#IBOutlet weak var tfThird: UITextField!
#IBOutlet weak var tfFourth: UITextField!
init() {
super.init(nibName: "TestBaumViewController", bundle: nil)
initializeTextFields()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//initializeTextFields()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
//initializeTextFields()
}
override func awakeFromNib() {
super.awakeFromNib()
//initializeTextFields()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func initializeTextFields() {
tfFirst.delegate = self // Error Here!
tfFirst.keyboardType = UIKeyboardType.ASCIICapable
tfSecond.delegate = self
tfSecond.keyboardType = UIKeyboardType.NumberPad
tfThird.delegate = self
tfThird.keyboardType = UIKeyboardType.ASCIICapable
tfFourth.delegate = self
tfFourth.keyboardType = UIKeyboardType.NumberPad
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
var result = true
let prospectiveText = (textField.text as NSString).stringByReplacingCharactersInRange(range , withString: string)
if textField == tfFirst {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "BW").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
let resultingStringLengthIsLegal = count(prospectiveText) <= 1
result = replacementStringIsLegal && resultingStringLengthIsLegal
}
}
if textField == tfSecond {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
let resultingStringLenthIsLegel = count(prospectiveText) <= 3
result = replacementStringIsLegal && resultingStringLenthIsLegel
}
}
if textField == tfThird {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "abcdefghijklmnopqrstuvwxyz").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
let resultingStringLenthIsLegel = count(prospectiveText) <= 1
result = replacementStringIsLegal && resultingStringLenthIsLegel
}
}
if textField == tfFourth {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
let resultingStringLenthIsLegel = count(prospectiveText) <= 3
result = replacementStringIsLegal && resultingStringLenthIsLegel
}
}
return result
}
As you can see i added IBOutlets for my textfields and now i wanted to add this view controller as their delegate. So i can check what was entered in the textfields.
I tried different approaches. First i tried putting the textfield.delegate = self into the viewDidLoad method but there i get an error "fatal error: unexpectedly found nil while unwrapping an Optional value" i think that is because the textfield aren't created jet. Next it tried the viewDidAppear method, with the same result. And finally, after i added an Object to the .xib with the view controller class set as its class to get the awakeFromNib method to fire, i put the textfield.delegate = self into that method. But i get the same error here.
Is there something i did not think of or am i doing something that will not be working?
regards Adarkas

Since you have already declared that your controller is conforming to the UITextFieldDelegate protocol, do this in the Interface Builder:
Select your textfield
Show Connections Inspector
There will be an Outlets section with delegate under it.
Drag the circle on the right of delegate to your View Controller object as shown under
Do this for every textField
The textField delegate methods should be called properly now.

What about didSet?
class TestBaumViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tfFirst: UITextField! {
didSet {
tfFirst.delegate = self
}
}
...
Or you can also drag the text fields delegates in the XIB.
Right click on the text field and drag the delegate property to the view controller.

Related

how can I add a addition feature into my Xcode project

I have a textfield in my firstViewContoller and thats where the user types in some numbers. Then in my secondViewController i have a label and in that label I want the number entered by the user to be shown. I have done till this but I dont know how I can take the value the user enters in the textfield every time and add it all up and show the result in the label. For example the user enters 5 so now the label is showing 5 then the user types in 20 and now i want the label to add that up and show 25 and keep on adding what the user enters.
// ViewController.swift
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var amountSpent: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
amountSpent.delegate = self
amountSpent.keyboardType = .numberPad }
private func amountSpent(_ amountSpent: UITextField,
shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let invalidCharacters = CharacterSet(charactersIn: "0123456789").inverted
return string.rangeOfCharacter(from: invalidCharacters) == nil }
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let resultViewController = segue.destination as! ResultViewController
resultViewController.recievedInt = amountSpent.text!
}
#IBAction func buttonPressed(_ sender: Any) {
self.performSegue(withIdentifier: "goToResult", sender: nil) } }
// ResultViewController.swift
import UIKit
class ResultViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var totalAmount: UILabel!
var recievedInt = ""
override func viewDidLoad() {
super.viewDidLoad()
totalAmount.text = recievedInt
}
}
Convert the new and the existing values from string to Int and add them together before setting the label to the new total
class ResultViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var totalAmount: UILabel!
var recievedInt = ""
override func viewDidLoad() {
super.viewDidLoad()
if let newValue = Int(recievedInt), let total = Int(totalAmount.text!) {
let newTotal = newValue + total
totalAmount.text = "\(newTotal)"
}
}
An alternative way to do it could be
override func viewDidLoad() {
super.viewDidLoad()
let newValue = Int(recievedInt) ?? 0
let total = Int(totalAmount.text!) ?? 0
let newTotal = newValue + total
totalAmount.text = "\(newTotal)"
}
Create a string variable to store the total value
var totalValue = "0"
Add the below method to your project. This will add all your entered values and will return the total value as a string.
private func getTotalCount(string: String) -> String {
let strTotal = "\(totalCount) + \(string)"
let arithmeticExpression = NSExpression(format: strTotal)
let additionResult = arithmeticExpression.expressionValue(with: nil, context: nil) as! Int
return String(additionResult)
}
You will click the done/return button after you entered the count in the text field, the delegate method will be triggered. Call the getTotalCount() method inside the delegate method as below:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
totalCount = self.getTotalCount(string: textField.text ?? "0")
textField.resignFirstResponder()
return true
}
Thus adding new counts will be automatically handled inside the UITextField delegate method. You just need to pass the totalValue to the next View Controller like this:
let resultViewController = segue.destination as! ResultViewController
resultViewController.recievedInt = totalCount

Swift: ProtocolDelegate optional value error

I want to delegate some tasks to the AcceptController, but my delegate property inside of 'SendController' always returns nil, so no delegation will ever be executed. I just can't figure out why my delegate property 'übergabeDelegate' always returns nil.
protocol ÜbergabeDelegate {
func übergebeText(text: String)
}
class SendController: UIViewController {
#IBOutlet weak var textField: UITextField!
var übergabeDelegate: ÜbergabeDelegate?
#IBAction func save(_ sender: UIButton) {
if let text = textField.text {
if übergabeDelegate != nil {
übergabeDelegate!.übergebeText(text: text)
} else {
print("\nübergabeDelegate is nil\n")
}
}
}
}
class AcceptController: UIViewController {
#IBOutlet weak var label: UILabel!
let sendController = SendController()
override func viewDidLoad() {
super.viewDidLoad()
sendController.übergabeDelegate = self
//print("Delegate gesetzt")
}
}
extension AcceptController: ÜbergabeDelegate {
func übergebeText(text: String) {
label.text = "\(text)"
}
}
I expect the label to present the input I gave on my SendController but the text of the label never actually changes.
inside viewDidLoad let sendController = SendController() creates a local variable. the sendController will then be released after viewDidLoad returns. set the sendController as a property of the AcceptController and the delegate will persist when you assign it because the SendController object will not be released after viewDidLoad returns.

Not able to set textfield as becomeFirstResponder() with textfield outlet collection in tvos

I took text field outlet collection and bind six text field over there.
I want to becomeFirstResponder of next text field which is in text field outlet collection.
I gave textfields tag 0 to 5 from storyboard.
see,
Main ViewController:
class ViewController: UIViewController {
#IBOutlet var txtSignUp: [UITextField]!
var arrayPlaceHolder:NSArray!
override func viewDidLoad() {
super.viewDidLoad()
arrayPlaceHolder = NSArray(array: ["1","2","3","4","5","6"])
self.setTextFieldValue()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func setTextFieldValue(){
for txtField in txtSignUp{
let tagTxt = txtField.tag
txtField.attributedPlaceholder = NSAttributedString(string:arrayPlaceHolder[tagTxt] as! String, attributes:[NSForegroundColorAttributeName:UIColor.black])
if(tagTxt != ((arrayPlaceHolder.count) - 1)){
txtField.returnKeyType = .next
}
txtField.delegate = self
}
}
}
extension ViewController:UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
for txt in txtSignUp{
let nextTxt = (textField.tag + 1)
if txt.tag == nextTxt {
txt.becomeFirstResponder()
break
}
}
return true
}
}
Error:
whose view is not in the window hierarchy!
Explanation:
In this code, I am not able to become next text field as becomeFirstResponder.
Can anyone help me to resolve this issue.
On TVos you have to use the textFieldDidEndEditing function because textFieldShouldReturn won't work to set the next responder:
class MyViewController: UIViewController{
#IBOutlet weak var firstTextField: UITextField!
#IBOutlet weak var secondTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
firstTextField.delegate = self
secondTextField.delegate = self
firstTextField.tag = 0
secondTextField.tag = 1
}
}
extension MyViewController: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
if (textField.tag == 0){
secondTextField.becomeFirstResponder()
}
}
}

How could I enable / disable keyboard Return Key manually in Swift?

This question is not duplicated from these:
How to disable/enable the return key in a UITextField?
How to enable or disable the keyboard return key
Enable and Disable Keyboard return key on demand in iOS
I have two TextFields.
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
textField1 has the Next button like the Return Key;
textField2 has the Go button like the Return Key;
textField1
textField2
I would like to enable the Go button of the second TextField just if both TextFields are not empty.
I tried to use someTextField.enablesReturnKeyAutomatically with TextFieldDelegate, but did not work.
Thank you for help.
Below: textField2 is disabled as long as textField1 is empty. If the latter is non-empty, we enable textField2, but enable the Go button only if textField2 is non-empty (via .enablesReturnKeyAutomatically property),
/* ViewController.swift */
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// text field delegates
textField1.delegate = self
textField2.delegate = self
// set return key styles
textField1.returnKeyType = UIReturnKeyType.Next
textField2.returnKeyType = UIReturnKeyType.Go
// only enable textField2 if textField1 is non-empty
textField2.enabled = false
// only enable 'go' key of textField2 if the field itself is non-empty
textField2.enablesReturnKeyAutomatically = true
}
// UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
if (textField1.text?.isEmpty ?? true) {
textField2.enabled = false
textField.resignFirstResponder()
}
else if textField == textField1 {
textField2.enabled = true
textField2.becomeFirstResponder()
}
else {
textField.resignFirstResponder()
}
return true
}
}
Runs as follows:
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField1.delegate = self
textField2.delegate = self
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField === textField2 {
setReturnKeyState(for: textField, isEnabled: shoulEnableReturnKey(), delay: 0.1) // A bit hacky it needs delay here
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField === textField2 {
if var text = textField.text, let range = Range(range, in: text) {
text.replaceSubrange(range, with: string)
setReturnKeyState(for: textField, isEnabled: shoulEnableReturnKey())
}
}
return true
}
private func shoulEnableReturnKey() -> Bool {
textField1.hasText && textField2.hasText
}
}
extension UITextFieldDelegate {
func setReturnKeyState(for textField: UITextField, isEnabled: Bool, delay: Double? = nil) {
textField.enablesReturnKeyAutomatically = false
if textField.delegate != nil {
if let delay = delay {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
textField.setValue(isEnabled, forKeyPath: "inputDelegate.returnKeyEnabled")
}
} else {
textField.setValue(isEnabled, forKeyPath: "inputDelegate.returnKeyEnabled")
}
}
}
}

Switching between Text fields on pressing return key in Swift

I'm designing an iOS app and I want that when the return key is pressed in my iPhone it directs me to the next following text field.
I have found a couple of similar questions, with excellent answers around but they all just happen to be in Objective-C and I'm looking for Swift code, now this is what I have up until now:
func textFieldShouldReturn(emaillabel: UITextField) -> Bool{
return true
}
It's placed in the file that's connected and controller to the UIView that contains the text fields, but I'm not sure if thats the right place.
Okay, so I tried this out and got this error:
//could not find an overload for '!=' that accepts the supplied arguments
func textFieldShouldReturn(textField: UITextField) -> Bool {
let nextTag: NSInteger = textField.tag + 1
// Try to find next responder
let nextResponder: UIResponder = textField.superview!.viewWithTag(nextTag)!
if (nextResponder != nil) {
// could not find an overload for '!=' that accepts the supplied arguments
// Found next responder, so set it.
nextResponder.becomeFirstResponder()
} else {
// Not found, so remove keyboard.
textField.resignFirstResponder()
}
return false // We do not want UITextField to insert line-breaks.
}
Make sure your UITextField delegates are set and the tags are incremented properly. This can also be done through the Interface Builder.
Here's a link to an Obj-C post I found: How to navigate through textfields (Next / Done Buttons)
class ViewController: UIViewController,UITextFieldDelegate {
// Link each UITextField (Not necessary if delegate and tag are set in Interface Builder)
#IBOutlet weak var someTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do the next two lines for each UITextField here or in the Interface Builder
someTextField.delegate = self
someTextField.tag = 0 //Increment accordingly
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Try to find next responder
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
// Not found, so remove keyboard.
textField.resignFirstResponder()
}
// Do not add a line break
return false
}
}
Swift 5
You can easily switch to another TextField when clicking return key in keyboard.
First, Your view controller conforms to UITextFieldDelegate and add the textFieldShouldReturn(_:) delegate method in ViewController
Drag from TextField to ViewController in Interface Builder. Then select the delegate option. Note : Do this for all TextField
Create an IBOutlet for all TextFields
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var txtFieldName: UITextField!
#IBOutlet weak var txtFieldEmail: UITextField!
#IBOutlet weak var txtFieldPassword: UITextField!
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == txtFieldName {
textField.resignFirstResponder()
txtFieldEmail.becomeFirstResponder()
} else if textField == txtFieldEmail {
textField.resignFirstResponder()
txtFieldPassword.becomeFirstResponder()
} else if textField == txtFieldPassword {
textField.resignFirstResponder()
}
return true
}
}
I suggest that you should use switch statement in textFieldShouldReturn(_:).
// MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
switch textField {
case nameTextField:
phoneTextField.becomeFirstResponder()
case phoneTextField:
emailTextField.becomeFirstResponder()
case emailTextField:
descriptionTextField.becomeFirstResponder()
default:
textField.resignFirstResponder()
}
return false
}
This approach needs some changes in table views and collection views, but it's okay for simple forms I guess.
Connect your textFields to one IBOutletCollection, sort it by its y coordinate and in textFieldShouldReturn(_:) just jump to the next textfield until you reach the end:
#IBOutlet var textFields: [UITextField]!
...
textFields.sortInPlace { $0.frame.origin.y < $1.frame.origin.y }
...
func textFieldShouldReturn(textField: UITextField) -> Bool {
if let currentIndex = textFields.indexOf(textField) where currentIndex < textFields.count-1 {
textFields[currentIndex+1].becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return true
}
Or just look at sample project (xcode 7 beta 4)
Swift & Programmatically
class MyViewController: UIViewController, UITextFieldDelegate {
let textFieldA = UITextField()
let textFieldB = UITextField()
let textFieldC = UITextField()
let textFieldD = UITextField()
var textFields: [UITextField] {
return [textFieldA, textFieldB, textFieldC, textFieldD]
}
override func viewDidLoad() {
// layout textfields somewhere
// then set delegate
textFields.forEach { $0.delegate = self }
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let selectedTextFieldIndex = textFields.firstIndex(of: textField), selectedTextFieldIndex < textFields.count - 1 {
textFields[selectedTextFieldIndex + 1].becomeFirstResponder()
} else {
textField.resignFirstResponder() // last textfield, dismiss keyboard directly
}
return true
}
}
Caleb's version in Swift 4.0
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = self.view.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return false
}
P.S. textField.superview? not working for me
I have tried many codes and finally this worked for me in Swift 3.0 Latest [March 2017]
The "ViewController" class should inherited the "UITextFieldDelegate" for making this code working.
class ViewController: UIViewController,UITextFieldDelegate
Add the Text field with the Proper Tag nuber and this tag number is used to take the control to appropriate text field based on incremental tag number assigned to it.
override func viewDidLoad() {
userNameTextField.delegate = self
userNameTextField.tag = 0
userNameTextField.returnKeyType = UIReturnKeyType.next
passwordTextField.delegate = self
passwordTextField.tag = 1
passwordTextField.returnKeyType = UIReturnKeyType.go
}
In the above code, the "returnKeyType = UIReturnKeyType.next" where will make the Key pad return key to display as "Next" you also have other options as "Join/Go" etc, based on your application change the values.
This "textFieldShouldReturn" is a method of UITextFieldDelegate controlled and here we have next field selection based on the Tag value incrementation
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
return true;
}
return false
}
the easiest way to change to next text Field is this no need for long code
override func viewDidLoad() {
super.viewDidLoad()
emailTextField.delegate = self
passwordTextField.delegate = self
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == emailTextField {
passwordTextField.becomeFirstResponder()
}else {
passwordTextField.resignFirstResponder()
}
return true
}
I have a good solution for your question.
STEP:
1 - Set your return key from the storyboard.
2 - In your swift file.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField.returnKeyType == .next {
Email.resignFirstResponder()
Password.becomeFirstResponder()
} else if textField.returnKeyType == .go {
Password.resignFirstResponder()
self.Login_Action()
}
return true
}
3 - Don't forget to set the delegate of the Textfield.
Thank you :)
Just use becomeFirstResponder() method of UIResponder class in your textFieldShouldReturn method. Every UIView objects are UIResponder's subclasses.
if self.emaillabel.isEqual(self.anotherTextField)
{
self.anotherTextField.becomeFirstResponder()
}
You can find more information about becomeFirstResponder() method at Apple Doc's in here.
Swift 4.2
This is a More Generic and Easiest Solution, you can use this code with any amount of TextFields.
Just inherit UITextFieldDelegate and update the Textfield Tag according to the order and copy this function
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let txtTag:Int = textField.tag
if let textFieldNxt = self.view.viewWithTag(txtTag+1) as? UITextField {
textFieldNxt.becomeFirstResponder()
}else{
textField.resignFirstResponder()
}
return true
}
An alternative method for purists who don't like using tags, and wants the UITextField delegate to be the cell to keep the components separated or uni-directional...
Create a new protocol to link the Cell's and the TableViewController.
protocol CellResponder {
func setNextResponder(_ fromCell: UITableViewCell)
}
Add the protocol to your cell, where your TextField Delegate is also the cell (I do this in the Storyboard).
class MyTableViewCell: UITableViewCell, UITextFieldDelegate {
var responder: CellResponder?
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
responder?.setNextResponder(self)
return true
}
}
Make your TableViewController conform to the CellResponder protocol (i.e. class MyTableViewController: UITableViewController, CellResponder) and implement the method as you wish. I.e. if you have different cell types then you could do this, likewise you could pass in the IndexPath, use a tag, etc.. Don't forget to set cell.responder = self in cellForRow..
func setNextResponder(_ fromCell: UITableViewCell) {
if fromCell is MyTableViewCell, let nextCell = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? MySecondTableViewCell {
nextCell.aTextField?.becomeFirstResponder()
} ....
}
No any special, here is my currently using to change the textFiled. So the code in ViewController looks good :). #Swift4
final class SomeTextFiled: UITextField {
public var actionKeyboardReturn: (() -> ())?
override init(frame: CGRect) {
super.init(frame: frame)
super.delegate = self
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.resignFirstResponder()
actionKeyboardReturn?()
return true
}
}
extension SomeTextFiled: UITextFieldDelegate {}
class MyViewController : UIViewController {
var tfName: SomeTextFiled!
var tfEmail: SomeTextFiled!
var tfPassword: SomeTextFiled!
override func viewDidLoad() {
super.viewDidLoad()
tfName = SomeTextFiled(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
tfName.actionKeyboardReturn = { [weak self] in
self?.tfEmail.becomeFirstResponder()
}
tfEmail = SomeTextFiled(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
tfEmail.actionKeyboardReturn = { [weak self] in
self?.tfPassword.becomeFirstResponder()
}
tfPassword = SomeTextFiled(frame: CGRect(x: 200, y: 0, width: 100, height: 100))
tfPassword.actionKeyboardReturn = {
/// Do some further code
}
}
}
If you have a lot of textfield components my be it could be better to use an outlet collection, linking textfields and setting Return Key from interface builder
#IBOutlet var formTextFields: [UITextField]!
override func viewDidLoad() {
for textField in formTextFields {
textField.delegate = self
}
}
extension RegisterViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let componentIndex = formTextFields.firstIndex(of: textField) {
if textField.returnKeyType == .next,
componentIndex < (formTextFields.count - 1) {
formTextFields[componentIndex + 1].becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
}
return true
}
}
Swift 4+
This piece of code will help you.
class YOURClass: UITextFieldDelegate {
override func viewDidLoad() {
//delegate your textfield in here
choosenTextField1.delegate = self
choosenTextField2.delegate = self
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
switch textField.tag {
case 1:
choosenTextField1.becomeFirstResponder()
case 2:
choosenTextField2.becomeFirstResponder()
default:
break
}
return true
}
}
You can go with field tags. I think that's easier than other.
First of all you have enter code hereto give tag to your field.
On my code usernameField tag is 0 and passwordField tag is 1. And I check my tag. Then doing proccess.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField.tag == 0 {
passwordField.becomeFirstResponder()
} else if textField.tag == 1 {
self.view.endEditing(true)
loginFunc()
} else {
print("Hata var")
}
return false
}
If click return on username field, go password.
Or If you click return when password field, run login function to login.
The viewWithTag is a bad solution because the superview may have views with tags set. This is better:
public extension Collection where Element: Equatable {
func element(after element: Element) -> Element? {
guard let index = firstIndex(of: element) else { return nil }
let nextIndex = self.index(after: index)
return nextIndex < endIndex ? self[nextIndex] : nil
}
}
class Controller: UIViewController {
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var companyTextField: UITextField!
private lazy var primaryTextFields: [UITextField] = {
[firstNameTextField, lastNameTextField, companyTextField]
}()
override func viewDidLoad() {
super.viewDidLoad()
primaryTextFields.forEach { $0.delegate = self }
}
}
extension Controller: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let next = primaryTextFields.element(after: textField) {
next.becomeFirstResponder()
} else if primaryTextFields.contains(textField) {
textField.resignFirstResponder()
}
return true
}
}

Resources