user3008901 user3008901 - 8 days ago 6
iOS Question

How To Add an Underline Border to a UITextField When it is a SubView of ScrollView

I am trying to programmatically create an underline border for a UITextfield when it is a subview of a UIScrollView in my iOS app built with Swift. I have managed to achieve this but only when the UITextfield is a subview of the view as the following screenshot of my app shows.

UITextfield with an Underline Border

Now I would like the UITextField to be a subview of a UIScrollView within the same view but the underline border does not show.

I successfully managed to create the underline border in the screenshot above by creating a CALayer in the viewDidLayoutSubviews method as follows.

let usernameTextField = UITextField()

override func viewDidLoad() {
usernameTextField.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(usernameTextField)
let constraints: [NSLayoutConstraint] = [
usernameTextField.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 20),
usernameTextField.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
usernameTextField.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor)
]
NSLayoutConstraint.activate(constraints)
}

override func viewDidLayoutSubviews() {
let textField = usernameTextField
let border = CALayer()
let width = CGFloat(1.0)
border.borderColor = UIColor(red:0.61, green:0.61, blue:0.61, alpha:1.0).cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)

border.borderWidth = width

textField.layer.addSublayer(border)

textField.layer.masksToBounds = true

}


But this won't work when the UITextField is a subview of a UIScrollView. This is what I have tried:

let usernameTextField = UITextField()
let scrollView = UIScrollView()

override func viewDidLoad() {
usernameTextField.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(usernameTextField)
view.addSubview(scrollView)
let scrollViewConstraints: [NSLayoutConstraint] = [
scrollView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20)
]

NSLayoutConstraint.activate(scrollViewConstraints)
let constraints: [NSLayoutConstraint] = [
usernameTextField.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 20),
usernameTextField.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
usernameTextField.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor)
]
NSLayoutConstraint.activate(constraints)
}

override func viewDidLayoutSubviews() {
let textField = usernameTextField
let border = CALayer()
let width = CGFloat(1.0)
border.borderColor = UIColor(red:0.61, green:0.61, blue:0.61, alpha:1.0).cgColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)

border.borderWidth = width

textField.layer.addSublayer(border)

textField.layer.masksToBounds = true

}


Can anyone suggest a way to make this work when the UITextField is a subview of a UIScrollView within the same view?

EDIT

I have accepted Matthias' answer where he has suggested I SubView a UIView as a border instead of a SubLayer.

let border = UIView()
border.backgroundColor =UIColor(red:0.61, green:0.61, blue:0.61, alpha:1.0)
border.translatesAutoresizingMaskIntoConstraints = false

textField.addSubview(border)

border.heightAnchor.constraint(equalToConstant: 1).isActive = true
border.widthAnchor.constraint(equalTo:textField.widthAnchor).isActive = true
border.bottomAnchor.constraint(equalTo: textField.bottomAnchor, constant: -1).isActive = true
border.leftAnchor.constraint(equalTo: textField.leftAnchor).isActive = true


This answers the question but just of curiosity I'd appreciate anyone who could also explain if it is possible to achieve the same with a SubLayer.

Answer

Instead of adding a subLayer, try just adding a subview :)

    let border = UIView()
border.backgroundColor =UIColor(red:0.61, green:0.61, blue:0.61, alpha:1.0)
                border.translatesAutoresizingMaskIntoConstraints = false

textField.addSubview(border)

            border.heightAnchor.constraint(equalToConstant: 1).isActive = true
            border.widthAnchor.constraint(equalTo:textField.widthAnchor).isActive = true
            border.bottomAnchor.constraint(equalTo: textField.bottomAnchor, constant: -1).isActive = true
            border.leftAnchor.constraint(equalTo: textField.leftAnchor).isActive = true
Comments