Lorenzo
Lorenzo

Reputation: 3387

How to get Width or Height of a UIView when I'm using "Equal width" constrain

I need help to solve this problem: I have a UITextFiled and I'm trying to apply a border at the bottom using this code:

func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
        let border = CALayer()
        border.backgroundColor = color.cgColor
        border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width)
        self.layer.addSublayer(border)
    }

The problem is that the result is not correct, the border goes outside the textfield because in the text Field I'm using the "Equal width constrain" and the Width at design time is not the same Width at "Didload()" time. There is a way to get the width to the textField after "Equal width constrain" correction?

Upvotes: 1

Views: 484

Answers (3)

DonMag
DonMag

Reputation: 77452

A much better approach is to

  • subclass UITextField
  • create the "underline border" layer on initialization
  • change the frame of that layer in layoutSubviews()

Example:

@IBDesignable
class UnderlinedTextField: UITextField {

    let underlineLayer: CALayer = CALayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    func commonInit() -> Void {
        layer.addSublayer(underlineLayer)
        underlineLayer.backgroundColor = UIColor.black.cgColor
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        underlineLayer.frame = CGRect(x: 0, y: bounds.height - 2.0, width: bounds.width, height: 2)
    }

}

Result (I gave the text field a background color of .cyan to make it easy to see):

enter image description here

It automatically resizes the "underline" when the field size changes - such as on device rotation:

enter image description here

Note that, by making it @IBDesignable, you can also see the underline layer during design-time.

This example uses a default color of black for the "underline" but you can change it via code just like any other property change, e.g.:

testField.underlineLayer.backgroundColor = UIColor.red.cgColor

Upvotes: 2

えるまる
えるまる

Reputation: 2551

Override bounds variable and call your border drawing in didSet. Your layer would be updated every time view changes bounds.

    var border = CALayer()

    init(frame: CGRect) {
        super.init(farme: frame)

        self.layer.addSublayer(border)
    }

    override var bounds: CGRect {
        didSet {
            addBottomBorderWithColor(color: .black, width: 2)
        }
    }

    func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
        border.backgroundColor = color.cgColor
        border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width)
        self.layer.setNeedsLayout()
    }

Upvotes: 1

Lorenzo
Lorenzo

Reputation: 3387

I found a possible solution by myself (not the perfect one). Because the Constrains are probably applied after DidLoad() and after viewDidLayoutSubviews(), I called the function to add the border inside the function viewDidAppear(). Now it works even if the new borders are shown with a small delay.

The best way is sub-class a UITextFiled as described here. Custom class that can be applied to every UITextField - Swift

In this case there the object is created correctly

Upvotes: 0

Related Questions