Nikita Zernov
Nikita Zernov

Reputation: 5635

UITextField: Bottom Border

I am creating bottom bordered textfield. I am subclass of UITextField. Here it is:

 @IBDesignable class LinedTextField: UITextField {

@IBInspectable var borderColor: UIColor = UIColor.whiteColor() {
    didSet {
        let border = CALayer()
        border.borderColor = self.borderColor.CGColor
        border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width:  self.frame.size.width, height: self.frame.size.height)

        border.borderWidth = borderWidth
        self.layer.addSublayer(border)
        self.layer.masksToBounds = true
    }
}

@IBInspectable var borderWidth: CGFloat = 0.5 {
    didSet {
        let border = CALayer()
        border.borderColor = self.borderColor.CGColor
        border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width:  self.frame.size.width, height: self.frame.size.height)

        border.borderWidth = borderWidth
        self.layer.addSublayer(border)
        self.layer.masksToBounds = true
    }
}

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

convenience init() {
    self.init(frame:CGRectZero)
    setup()
}

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


override func awakeFromNib() {
    super.awakeFromNib()
    setup()
}

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    setup()
}

func setup() {
    let border = CALayer()
    border.borderColor = self.borderColor.CGColor
    border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width:  self.frame.size.width, height: self.frame.size.height)

    border.borderWidth = borderWidth
    self.layer.addSublayer(border)
    self.layer.masksToBounds = true
}

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

Then in interface builder I set that 2 properties(border colour and border width) and everything looks good:enter image description here

But when I run application on my real 5.5" device, it looks this way:enter image description here

Border is not long as the text field. What's wrong here?

Upvotes: 1

Views: 3716

Answers (3)

Julien Quere
Julien Quere

Reputation: 2459

I think it's because the border frame need to be computed on layoutSubviews. Here is an example on how to do so (plus a simplification of your code):

Supported in Swift 3

  @IBDesignable class UnderlinedTextField: UITextField {

let border = CALayer()

@IBInspectable var borderColor: UIColor = UIColor.white {
    didSet {
        setup()
    }
}

@IBInspectable var borderWidth: CGFloat = 0.5 {
    didSet {
        setup()
    }
}

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

convenience init() {
    self.init(frame:CGRect.zero)
    setup()
}

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


override func awakeFromNib() {
    super.awakeFromNib()
    setup()
}

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    setup()
}

func setup() {
    border.borderColor = self.borderColor.cgColor
    border.borderWidth = borderWidth
    self.layer.addSublayer(border)
    self.layer.masksToBounds = true
}

override func layoutSubviews() {
    super.layoutSubviews()
    border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width:  self.frame.size.width, height: self.frame.size.height)
}

override func textRect(forBounds bounds: CGRect) -> CGRect {
    return editingRect(forBounds: bounds)
}

override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
    return editingRect(forBounds: bounds)
}

override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: 10, dy: 0)
}

}

EDIT: I Added code for the text area. In this example, there is a 20px horizontal inset. There in more infos on editingRectForBounds (and its friends) in the Apple's doc: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextField_Class/#//apple_ref/occ/instm/UITextField/textRectForBounds:

Upvotes: 3

Jayesh Miruliya
Jayesh Miruliya

Reputation: 3317

  let border = CALayer()
  border.borderColor = UIColor.blackColor().CGColor
  border.frame = CGRectMake(-30, textField.frame.size.height - 1.0, textField.frame.size.width*1.5 , 1.0)
  border.borderWidth = 1.0
  textField.layer.addSublayer(border)
  textField.layer.masksToBounds = true

Upvotes: 0

Erkam KUCET
Erkam KUCET

Reputation: 514

import UIKit

@IBDesignable
class MyTextField: UITextField {

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

        setupView()
    }

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

        setupView()
    }

    func setupView(){

        self.borderStyle = UITextBorderStyle.None
        let border = CALayer()
        let borderWidth: CGFloat = 2
        border.borderColor = UIColor(red: 5/255, green: 84/255, blue: 115/255, alpha: 1.0).CGColor
        border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, self.frame.size.height)
        border.borderWidth = borderWidth
        self.layer.addSublayer(border)

    }

}

Upvotes: 0

Related Questions