Search code examples
iosswiftuitextfielduilabel

Add UILabel as subview of UITextField on top


I am in the process of implementing a UILabel as a subview of a UITextField which will be shown right above the UITextField itself. The UITextField has a rounded border and what I would like to achieve is the UILabel to be shown over the border.

Everything currently works as expected, but the UILabel is drawn behind the border of the UITextField. I want it to go "over" (above) the border so the white backgroundColor would be shown above part of the border and make the text more easily readible.

var priceTextField: CustomTextField = {

    let priceTextField = CustomTextField()
    priceTextField.layer.cornerRadius = 10.0
    priceTextField.layer.borderWidth = 1.0
    priceTextField.layer.borderColor = UIColor.darkGray.cgColor
    priceTextField.translatesAutoresizingMaskIntoConstraints = false
    priceTextField.font = UIFont.systemFont(ofSize: 15)
    priceTextField.textColor = .black
    priceTextField.text = "0"
    priceTextField.suffix = "EUR"
    priceTextField.suffixTextColor = .darkGray
    priceTextField.suffixSpacing = 2.0
    priceTextField.textAlignment = .center
    priceTextField.labelText = "Price"

    return priceTextField

}()

In my CustomTextField class (subclass of UITextField):

public var labelText: String?

var topLabel: UILabel = {

    let topLabel = UILabel()
    topLabel.translatesAutoresizingMaskIntoConstraints = false
    topLabel.textAlignment = .center
    topLabel.font = UIFont.systemFont(ofSize: 12)
    topLabel.textColor = .lightGray
    topLabel.backgroundColor = .white
    topLabel.numberOfLines = 1
    return topLabel

}()

func setupLabel() {

    self.addSubview(topLabel)
    topLabel.centerYAnchor.constraint(equalTo: self.topAnchor).isActive = true
    topLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true
    topLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
    topLabel.text = labelText

}

I call setupLabel() at the end of the draw(_ rect: CGRect) method of UITextField (because I work with this to show the EUR sign always behind the entered value).

I have tried to play around with bringSubviewToFront and changing the zPosition of the layer of the UILabel, without success.

It now looks like this:

How can I bring the text "above" the border on the top?

EDIT: Tried Sh_Khan's solution, but it's still hidden behind the border.

import Foundation
import UIKit

public class CustomTextView: UIView, UITextFieldDelegate {

    public var labelText: String?

    var customTextField: CustomTextField = {

        let customTextField = CustomTextField()
        customTextField.translatesAutoresizingMaskIntoConstraints = false
        customTextField.font = UIFont.systemFont(ofSize: 15)
        customTextField.textColor = .black
        customTextField.textAlignment = .center
        customTextField.text = "0"
        customTextField.suffix = "EUR"
        customTextField.suffixTextColor = .lightGray
        customTextField.suffixSpacing = 2.0

        return customTextField

    }()

    var topLabel: UILabel = {

        let topLabel = UILabel()
        topLabel.translatesAutoresizingMaskIntoConstraints = false
        topLabel.font = UIFont.systemFont(ofSize: 12)
        topLabel.textColor = .darkGray
        topLabel.numberOfLines = 1
        topLabel.backgroundColor = .red
        topLabel.textAlignment = .center

        return topLabel

    }()

    override public init(frame: CGRect) {

        super.init(frame: frame)
        setupBorders()

    }

    public override func layoutSubviews() {

        setupViews()

    }

    func setupBorders() {

        self.layer.cornerRadius = 10.0
        self.layer.borderColor = UIColor.lightGray.cgColor
        self.layer.borderWidth = 1.0

    }

    func setupViews() {

        addSubview(topLabel)
//        insertSubview(topLabel, aboveSubview: customTextField)
        insertSubview(customTextField, belowSubview: topLabel)

        customTextField.topAnchor.constraint(equalTo: topAnchor).isActive = true
        customTextField.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        customTextField.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        customTextField.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

        topLabel.centerYAnchor.constraint(equalTo: topAnchor).isActive = true
        topLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
        topLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true

        topLabel.text = labelText

    }

    public required init?(coder aDecoder: NSCoder) {

        super.init(coder: aDecoder)
        setupViews()

    }

}

Solution

  • You can try to organize it by creating a UIView subclass , so everything appear properly in it's order of adding

    class CustomView: UIView {
    
        var priceTextField: CustomTextField = {
    
            let priceTextField = CustomTextField()
            priceTextField.layer.cornerRadius = 10.0
            priceTextField.layer.borderWidth = 1.0
            priceTextField.layer.borderColor = UIColor.darkGray.cgColor
            priceTextField.translatesAutoresizingMaskIntoConstraints = false
            priceTextField.font = UIFont.systemFont(ofSize: 15)
            priceTextField.textColor = .black
            priceTextField.text = "0"
            priceTextField.suffix = "EUR"
            priceTextField.suffixTextColor = .darkGray
            priceTextField.suffixSpacing = 2.0
            priceTextField.textAlignment = .center
            priceTextField.labelText = "Price"
    
            return priceTextField
    
        }() 
        var topLabel: UILabel = {
    
            let topLabel = UILabel()
            topLabel.translatesAutoresizingMaskIntoConstraints = false
            topLabel.textAlignment = .center
            topLabel.font = UIFont.systemFont(ofSize: 12)
            topLabel.textColor = .lightGray
            topLabel.backgroundColor = .white
            topLabel.numberOfLines = 1
            return topLabel
    
        }()
    
       var lableStr:String?
       init(frame: CGRect,lblTex:String) {
        super.init(frame: frame)
           lableStr = lblTex
           createSubviews()
        }
    
        override init(frame: CGRect) {
        super.init(frame: frame)
           createSubviews()
        }
        required init?(coder aDecoder: NSCoder) {
           super.init(coder: aDecoder)
           createSubviews()
        }
        func createSubviews() {
           // all the layout code from above
           // add the textfield then the label and set constraints properly
        }
    }