I am trying to write a simple composite component for iOS in Swift 3. It consists of a UILabel followed by an UITextField laid out horizontally followed by a line under them. But What happens is the UILabel disappears, UITextField appears on the parent view and line also disappears.
What it actually looks like in the Storyboard
My component's constraints in the view controller
My intention was to use Auto Layout, anchor the label to top and leading anchors of the view, anchor the textfield to top of the view and trailing anchor of the label with a constant, so they would appear side by side.
I did do a lot of research on this, one site that looked pretty close to what I wanted was https://www.raywenderlich.com/125718/coding-auto-layout, and I think I am following more or less the same approach.
I am doing something obviously wrong, but can't figure out what. Any help is much appreciated, I have been at this for a few days now.
import UIKit
@IBDesignable
class OTextEdit: UIView {
@IBInspectable var LabelText: String = "Label"
@IBInspectable var SecureText: Bool = false
@IBInspectable var Color: UIColor = UIColor.black
@IBInspectable var Text: String = "" {
didSet {
edit.text = Text
}
}
fileprivate let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 35))
fileprivate let edit = UITextField(frame: CGRect(x: 210, y: 0, width: 200, height: 35))
fileprivate let line: UIView = UIView()
override var intrinsicContentSize: CGSize {
return CGSize(width: 300, height: 100)
}
func setup() {
label.text = LabelText
label.textColor = Color
label.font = UIFont(name: "Avenir Next Condensed", size: 24)
edit.font = UIFont(name: "Avenir Next Condensed", size: 24)
edit.borderStyle = .roundedRect
edit.isSecureTextEntry = SecureText
line.backgroundColor = UIColor.white
self.addSubview(label)
self.addSubview(edit)
self.addSubview(line)
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
setup()
setupConstaints()
}
func setupConstaints() {
label.translatesAutoresizingMaskIntoConstraints = false
edit.translatesAutoresizingMaskIntoConstraints = false
line.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: -10).isActive = true
label.topAnchor.constraint(equalTo: topAnchor)
edit.leadingAnchor.constraint(equalTo: label.leadingAnchor, constant: 10).isActive = true
edit.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
edit.topAnchor.constraint(equalTo: self.topAnchor)
line.heightAnchor.constraint(equalToConstant: 2.0).isActive = true
line.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
line.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
line.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 1.0).isActive = true
}
}
You haven't got a series of constraints top to bottom, so auto layout can't determine the content size of your object. You have tried to set this via the initrinsicContentSize
but you shouldn't need to do this.
You also need to set a horizontal hugging priority for your label to let auto layout know that you want the text field to expand:
I removed your override of intrinsicContentSize
and changed your constraints to:
func setupConstraints() {
label.translatesAutoresizingMaskIntoConstraints = false
edit.translatesAutoresizingMaskIntoConstraints = false
line.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
label.topAnchor.constraint(equalTo: topAnchor)
label.bottomAnchor.constraint(equalTo: line.topAnchor, constant: -8).isActive = true
edit.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 10).isActive = true
edit.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
edit.firstBaselineAnchor.constraint(equalTo: label.firstBaselineAnchor).isActive = true
line.heightAnchor.constraint(equalToConstant: 2.0).isActive = true
line.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
line.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
line.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 1.0).isActive = true
line.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
I think it is pretty close to what you are after.