Box House
Box House

Reputation: 177

How to go back when the UITextfield is empty in Swift code?

My question is: When the UITextField is empty, how do I click the "Backspace" button to go to the previous UITextField? I have been struggling trying to do this in my code below?

Second Question: How do I only allow 1 character to get entered in the UITextField?

I am new at Swift code and trying to learn. Any help would be great.

What I am trying to do is have the user be able to type in a code in the 6 UITextFields and be able to click the "Backspace" button on any one of the UITextFields with only allowing the user to enter one number in each UITextField.

enter image description here

Code Below:

@objc func textFieldDidChange(textfield: UITextField) {
    let text = textfield.text!
    if text.utf16.count == 0 {
        switch textfield {
        case textField2:
            textField1.becomeFirstResponder()
            textField1.backgroundColor = UIColor.blue
            textField1.tintColor = .clear
        case textField3:
            textField2.becomeFirstResponder()
            textField2.backgroundColor = UIColor.blue
            textField2.tintColor = .clear
        case textField4:
            textField3.becomeFirstResponder()
            textField3.backgroundColor = UIColor.blue
            textField3.tintColor = .clear
        case textField5:
            textField4.becomeFirstResponder()
            textField4.backgroundColor = UIColor.blue
            textField4.tintColor = .clear
        case textField6:
            textField5.becomeFirstResponder()
            textField5.backgroundColor = UIColor.blue
            textField5.tintColor = .clear
            textField6.resignFirstResponder()
            textField6.backgroundColor = UIColor.blue
            textField6.tintColor = .clear
        default:
            break
        }
    }
    else if text.utf16.count == 1 {
        switch textfield {
        case textField1:
            textField1.backgroundColor = UIColor.black
            textField1.textColor = .white
            textField1.tintColor = .clear
            textField2.becomeFirstResponder()
            textField2.backgroundColor = UIColor.black
            textField2.textColor = .white
            textField2.tintColor = .clear
        case textField2:
            textField3.becomeFirstResponder()
            textField3.backgroundColor = UIColor.black
            textField3.textColor = .white
            textField3.tintColor = .clear
        case textField3:
            textField4.becomeFirstResponder()
            textField4.backgroundColor = UIColor.black
            textField4.textColor = .white
            textField4.tintColor = .clear
        case textField4:
            textField5.becomeFirstResponder()
            textField5.backgroundColor = UIColor.black
            textField5.textColor = .white
            textField5.tintColor = .clear
        case textField5:
            textField6.becomeFirstResponder()
            textField6.backgroundColor = UIColor.black
            textField6.textColor = .white
            textField6.tintColor = .clear
        case textField6:
            textField6.resignFirstResponder()
        default:
            break

        }
    } 
}

Upvotes: 2

Views: 2267

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

I'd just like to point out that I'm still relatively new to iOS and Swift in general, but even with just a few minutes of searching, I was able to find some seeds of ideas which provided me with the suggested solution.

Based on your (improved) question, I believe a different approach is required. What you really don't want to use a text component. "Why"? I here you ask. Because they don't actually provide you with the functionality that you want and come with a considerable overhead.

For this, what you really want is more control. You want to know when a key is pressed and you want to respond to it (I know, sounds like a text component, but) and be notified when more extended functionality occurs, like the delete key is pressed.

After a few minutes of research, some trial and error, I found that the UIKeyInput is more along the lines of what you want.

It will tell you when text is inserted and, more importantly, will tell you when Delete is pressed

The added benefit is, you can filter the input directly. You can take the first character from the String and ignore the rest or auto fill the following elements with the remaining text. You can perform validation (for numerical only content) and what ever else you might want to do

So, I started a really new project, added a UILabel to the UIViewController in the storyboard, bound it to the source and implemented the UIKeyInput protocol as such...

class ViewController: UIViewController {

    override var canBecomeFirstResponder: Bool {
        return true
    }

    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear(_ animated: Bool) {
        becomeFirstResponder()
    }

}

extension ViewController: UIKeyInput {

    var hasText: Bool {
        return true
    }

    func insertText(_ text: String) {
        print(text)
        label.text = text
    }

    func deleteBackward() {
        print("Delete backward")
    }

}

I ran the project and when a key was typed, the label was updated with the new key and when delete was pressed, the Delete backward text was printed to console.

Now. You have some choices to make. To use a single UIViewController and (maybe) a series of UILabels and manage interactions within it, so when a key is typed, you present the next label as the input focus (and when delete is pressed, you move back) or do you create a series of UIControls which represent each digit and manage via some delegate call back process.

You may also need to implement the UITextInputTraits protocol, which will allow you to control the keyboard presented

You might also like to have a read through Responding to Keyboard Events on iOS, CustomTextInputView.swift and Showing the iOS keyboard without a text input which were just some of the resources I used to hobble this basic example together with.

Upvotes: 2

Arash Etemad
Arash Etemad

Reputation: 1909

you can use this extension for your second question:

import UIKit

private var maxLengths = [UITextField: Int]()
extension UITextField {
    @IBInspectable var maxLength: Int {
        get {
            guard let length = maxLengths[self] else {
                return Int.max
            }
            return length
        }
        set {
            maxLengths[self] = newValue
            addTarget(
                self,
                action: #selector(limitLength),
                for: UIControlEvents.editingChanged
            )
        }
    }

    @objc func limitLength(textField: UITextField) {
        guard let prospectiveText = textField.text,
            prospectiveText.count > maxLength
            else {
                return
        }

        let selection = selectedTextRange
        let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
        text = prospectiveText.substring(to: maxCharIndex)
        selectedTextRange = selection
    }
}

when you add this extension to your project you can see an extra attribute in "Attribute Inspector" tab and you can set the max length of UITextField.

Upvotes: 1

Related Questions