Identifying UITextField when using a UITextField Collection in Swift iOS - ios

I am creating a signup screen.
There are four UITextField, which is the ID, password, password check, name,
I am #Iboutlet var signupTextFields: [UITextField]! I connected it. After that, I want to make an ID, password validation.
First, I divided ViewController and UItextFieldDelegate.
class SignUpViewController: UIViewController {
#IBOutlet var signUpTextFields: [UITextField]! {
didSet {
signUpTextFields.forEach { textField in
textField.delegate = textFieldDelegate
textField.returnKeyType = .next
}
}
}
#IBOutlet weak var nextButton: UIButton!
private lazy var textFieldDelegate = TextFieldDelegate(self)
override func viewDidLoad() {
super.viewDidLoad()
signUpTextFields.first?.becomeFirstResponder()
}
#IBAction func nextButtonTapped(_ sender: UIButton) {
}
}
class TextFieldDelegate: NSObject, UITextFieldDelegate {
private weak var signUpViewController: SignUpViewController?
init(_ signUpViewController: SignUpViewController) {
self.signUpViewController = signUpViewController
}
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.layer.borderWidth = 1
textField.layer.borderColor = UIColor.systemBlue.cgColor
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
textField.layer.borderColor = UIColor.black.cgColor
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
The problem when using the functions provided by Delegate is that the example code is to identify UITextField using if-else, such as
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == idTextField {
//code
} else if textField == passwordTextField {
//code
}
}
I was not this way, but I thought I wanted to abstract the uitextfield a little more to use the Factory method or polymorphism.
Is there a way to identify a UITextField Collection without using if-Else?

I'd recommend - Tag + Enum. (tag field is the norm to identify a view instance from Storyboard / Xib in the cases where you don't have individual IBOutlets)
Set "tag" in the Storyboard - ensure they are unique. (simple index oughta be enough -- 0, 1, 2 .. etc.)
Create an enum inside the view controller.
enum TextField {
case name = 0
case password = 1
}
& so on (explicitly declare the tag values in the enum)
Use Switch instead of if-else for identification.
switch textField.tag {
case .name:
case .password:
}
This should suffice for your case (since you are just going through an example code). But it's good that you are interested in clean code -- I'd recommend creating the TextFields programmatically & using the enum to set the .tag field.

Using the same delegate for all of the text fields was bad design if your intention was to behave differently in the delegate methods. If it’s too late to change that, I would recommend an array of closures corresponding to the array of text fields. That way, calling the right closure is a one-liner based on firstIndex(of:).

Related

How can I override a Swift delegate method to take more parameters?

I have a form with 3 UITextFields. I'd like to validate the user input for each field, when the user is done inputing text in that specific field. Right now, I've got a method
validateAllFields()
that I call in:
func textFieldDidEndEditing(_ textField: UITextField) {
self.validateAllFields()
}
I'd rather validate a single field, after its text has been modified, not validate all fields after each one has been modified.
Is there a ways to override a delegate method or extend UITextField to take more parameters? Something like:
override func textFieldDidEndEditing(_ textField: UITextField,
textFieldIdentifier: TextFieldIdentifierEnum) {
self.validate(textField: textField, basedOn: textFieldIdentifier)
}
I suspect it can be done with an extension, but I'm unclear how to proceed.
Thanks for the help!
You don't have to as the paramter (_ textField: UITextField) gives you the current textfield the user changes
Suppose you have
#IBOutlet weak var emailTexf:UITextField!
#IBOutlet weak var passTexf:UITextField!
func textFieldDidEndEditing(_ textField: UITextField) {
self.validateAllFields(textField)
}
fun validateAllFields(_ current:UITextField) {
if emailTexf == current {
}
else if passTexf == current {
}
else { } // etc
}

Hiding the Keyboard triggered by textField via resignFirstResponder

Environment: Xcode Version 8.2 (8C38)/Swift 3.0
A textFiled object in the View is wire up to a method named textFieldReturn in the controller via IBAction. The related codes are presented as follow
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func textFieldReturn(_ sender: Any) {
_ = (sender as AnyObject).resignFirstResponder()
}
}
What I expect:
When I hit the Return key of the virtual keyboard the function textFieldReturn(_:) will be called and the keyboard will be hidden
Issue Observer:
The function is not called after I tapped the return key, the keyboard is still there
Resource:
This code spinet come from the example of the Chapter 16 of the book iOS 10 App Development Essentials by Neil Symth (pp-114)
The only difference between this code and original code is the type of the function argument (Sender). It is AnyObject in the original book while I've got Any by default, therefore I've cast to AnyObject inside the function body
Question:
Its seems to be a decent book, but the sample code doesn't work for me. How can I call the resignFirstResponder() method when I hit the return key
Alternative try out:
Instead of using IBAction, I turn to the idea of delegate, I've set the VeiwController as the delegate of the textField
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tempText: UITextField! //reference the TextField as the variable **tempText** in the controller
override func viewDidLoad() {
super.viewDidLoad()
self.tempText.delegate = self //set up the delegation
}
func textFieldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return(true)
}
}
Problem
The alternative solution still not working.
Thanks for your time and help
Why are you not using the original delegate function of UITextField?
I think the default function will work as you want:
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tempText: UITextField! //reference the TextField as the variable **tempText** in the controller
override func viewDidLoad() {
super.viewDidLoad()
self.tempText.delegate = self //set up the delegation
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool{
textField.resignFirstResponder()
return false
}
}
Replace your textFieldReturn method with this and it should work just fine.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
Make sure to keep the following in your viewDidLoad()
self.tempText.delegate = self

Clear a Textfield if two are completed

I'm writing an app for iOS where I have 3 values, and every value is the result of two the others two. So, if you compile two of the three you have the third value.
Right now I have to clear the value inside the Texfield manually before calculate the third value otherwhise the app dont work. What I want to do is that when I compile the first and the second textfield the third clear automatically.
In practise I want to check the last two entered textfield and clear the other.
How can I check this statement in swift?
Thank you
try to use TextFieldDelegate for this, in the case you are training to display this may help
class ViewController: UIViewController,UITextFieldDelegate //set delegate to class
#IBOutlet var TF1: UITextField
#IBOutlet var TF2: UITextField
#IBOutlet var TF3: UITextField
override func viewDidLoad() {
super.viewDidLoad()
TF1.delegate = self //set delegate to textfile
TF2.delegate = self //set delegate to textfile
TF3.delegate = self //set delegate to textfile
}
func textFieldDidBeginEditing(textField: UITextField!) { //delegate method
}
func textFieldShouldEndEditing(textField: UITextField!) -> Bool { //delegate method
return false
}
func textFieldShouldReturn(textField: UITextField!) -> Bool { //delegate method
textField.resignFirstResponder()
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
if(TF1.text != "" && TF2.text != ""){
TF3.text = ""
}
}
I hope this can help you

iOS: How to get the current visible keyboard type?

How do I find out if the keyboard is of type numeric, Twitter, email, etc...?
edit: Is there a way to detect keyboard type without using an outlet?
Consider that you have tow textFields in the ViewController, You will need to implement textFieldShouldBeginEditing method from UITextFieldDelegate protocol, as follows:
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tfEmail: UITextField!
#IBOutlet weak var tfPassword: UITextField!
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField.keyboardType == .emailAddress {
// this is the tfEmail!
}
if textField.isSecureTextEntry {
// this is tfPassword!
}
}
}
Make sure their delegates are connected to the ViewController, programmatically:
tfEmail.delegate = self
tfPassword.delegate = self
or from the Interface Builder.
Note that you can recognize the keyboard type for the current textField by checking its keyboardType property, which is an instance of UIKeyboardType enum:
The type of keyboard to display for a given text-based view. Used with
the keyboardType property.
What about UITextView?
The same exact functionality should be applied when working with UITextViews, but you need to implement textViewDidBeginEditing(_:) method from UITextViewDelegate protocol instead of implementing textFieldShouldBeginEditing. Again, make sure the delegate of the textView is connected to the ViewController.
Also,
If your main purpose of checking the keyboard type is just for recognizing what is the current responded textField/textView, I suggest to do a direct check:
class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {
#IBOutlet weak var tfEmail: UITextField!
#IBOutlet weak var tfPassword: UITextField!
#IBOutlet weak var textViewDescription: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
tfEmail.delegate = self
tfPassword.delegate = self
textViewDescription.delegate = self
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField === tfEmail {
// this is the tfEmail!
}
if textField === tfPassword {
// this is tfPassword!
}
}
func textViewDidBeginEditing(_ textView: UITextView) {
if textView === textViewDescription {
// this is description textview
}
}
}
For more information about === operator you might want to check this question/answers.
Hope this helped.
In addition to Ahmad F 's great answer, this is my approach of getting the current keyboard type, at any time:
Step 1: Delegate UITextField
class File: UIViewController, UITextFieldDelegate{//...}
Update viewDidLoad() to this:
#IBOutlet weak var normalTextField: UITextField!
#IBOutlet weak var numberTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
numberTextField.keyboardType = .numberPad
normalTextField.keyboardType = .default
emailTextField.keyboardType = .emailAddress
numberTextField.delegate = self
normalTextField.delegate = self
emailTextField.delegate = self
}
Step 2: Working with UITextField's methods:
Add a variable called keyboardType, as below:
var keyboardType: UIKeyboardType? = nil
Then, change it whenever a new textField begins editing:
func textFieldDidBeginEditing(_ textField: UITextField) {
keyboardType = textField.keyboardType
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
keyboardType = nil
return true
}
Step 3: Create and call a function like below:
func getCurrentKeyboard() -> String{
if keyboardType == nil{
return "no current keyboard"
}
else if keyboardType == .numberPad{
return "number"
}
else if keyboardType == .emailAddress{
return "email"
}
else{
return "default"
}
}
#IBAction func displayCurrentKeyboard(_ sender: UIButton) {
print(self.getCurrentKeyboard())
}
And this outputs: email / number / no current keyboard / default, depending on the case.
If you want to check which type of keyboard it is with if-else statements, you can change your displayCurrentKeyboard() method to this:
#IBAction func displayCurrentKeyboard(_ sender: UIButton) {
let keyboardString = self.getCurrentKeyboard()
if keyboardString == "number"{
//...
}
else if keyboardString == "email"{
//...
}
else{
//...
}
}
And that's it! You can call this wherever you want in your code with this usage:
let keyboardString = self.getCurrentKeyboard()
NOTE: This method also handles the case of no keyboard visible on the screen, returning no current keyboard, in this case.
Let me know if this helps!

How to distinguish UITextFields in delegate methods?

I have the following code:
class ViewController: UIViewController, UITextFieldDelegate {
// MARK: Properties
#IBOutlet weak var layersTextField: UITextField!
#IBOutlet weak var innerShapeTextField: UITextField!
#IBOutlet weak var outerShapeTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
layersTextField.delegate = self
innerShapeTextField.delegate = self
outerShapeTextField.delegate = self
}
// MARK: UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(textField: UITextField) {
// do something
}
}
Now in textFieldDidEndEditing(_:) I would like to do something, dependent on which UITextField called this method.
Is there any way to distinguish, which UITextField did this? Is there some kind of ID or identifier I can set on the UITextFields?
You can make this determination using one of two approaches: outlets or tags. For the outlet approach, declare an outlet instance variable (using the IBOutlet keyword) and then make an outlet connection. In your delegation method, test whether the passed-in text object is the same object referenced by the outlet, using pointer comparison.
For example, say you declare and connect an outlet named SSN. Your code might look something like Listing 3-1:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
if (textField == SSN) {
// ...
return NO;
}
return YES;
}
// Translated to Swift:
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
if textField === SSN {
// ...
return false
}
return true
}
You can check by the name of the next filed. if textField == layersTextField { //do what you want } and you can do that for any text field you need a specific action for.
You can create an IBAction instead:

Resources