Search code examples
swiftuitextfielduitextinput

Custom UITextfield with discontinuous bottom borders


Here is the result I want to achieve

I am now working on a UITextfield. I hope to know how to add four discontinuous bottom border to a UITextfield, and how to make the space between input digits larger to make them fit exactly on the four lines respectively. Moreover, if possible, how to make the line become black (while other lines remain grey) when users are inputing digit on that line? Thank you so much!


Solution

  • Use following subclass of UITextField and create textfield for each digit either in storyboard or programatically.

    Note that each textfield has to set a tag, such as

    1st Digit: textField1.tag=1

    2nd Digit: textField1.tag=2

    3rd Digit: textField1.tag=3

    4th Digit: textField1.tag=4

    class CustomTextField: UITextField {
        private let normalStateColor = UIColor.lightGray.cgColor
        private let focusStateColor = UIColor.black.cgColor
    
        private let border = CALayer()
        private let borderHeight: CGFloat = 4.0
    
        // MARK:- Init
        required init?(coder aDecoder: NSCoder) {
            super.init(coder:aDecoder)
            setup()
        }
    
        override init(frame:CGRect) {
            super.init(frame:frame)
            setup()
        }
    
        override func awakeFromNib() {
            super.awakeFromNib()
            setup()
        }
        // MARK:- Overrides
        override func layoutSubviews() {
            super.layoutSubviews()
    
            let size = self.frame.size
            self.border.frame = CGRect(x: 0, y: size.height - borderHeight, width: size.width, height: borderHeight)
        }
    
        override func willMove(toSuperview newSuperview: UIView!) {
            guard newSuperview != nil else {
                NotificationCenter.default.removeObserver(self)
                return
            }
    
            NotificationCenter.default.addObserver(self, selector: #selector(beginEdit),
                                                   name: UITextField.textDidBeginEditingNotification, object: self)
            NotificationCenter.default.addObserver(self, selector: #selector(endEdit),
                                                   name: UITextField.textDidEndEditingNotification, object: self)
        }
    
        @objc func beginEdit() {
            border.backgroundColor = self.focusStateColor
        }
    
        @objc func endEdit() {
            border.backgroundColor = self.normalStateColor
        }
    
        private func setup() {
            border.backgroundColor = self.normalStateColor
            textAlignment = .center
            borderStyle = .none
            layer.addSublayer(border)
            delegate = self
        }
    }
    
    extension CustomTextField: UITextFieldDelegate {
    
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            if textField.text!.count < 1  && string.count > 0 {
                textField.text = string
                textField.superview?.viewWithTag(textField.tag + 1)?.becomeFirstResponder()
                return false
            } else if textField.text!.count >= 1  && string.count == 0 {
                textField.text = ""
                textField.superview?.viewWithTag(textField.tag - 1)?.becomeFirstResponder()
                return false
            }
    
            return true
        }
    }
    

    That yields

    enter image description here