I have convenience extension functions that allow me to add constraints to UIViews:
enum Constraint : String {
case top = "topAnchor"
case bottom = "bottomAnchor"
case right = "rightAnchor"
case left = "leftAnchor"
case centerX = "centerXAnchor"
case centerY = "centerYAnchor"
}
extension UIView {
func constraintLeft(toLeft of: UIView, margin: CGFloat = 0) {
self.deleteConstraints(.left)
print(self.constraints) // prints []
let left = leftAnchor.constraint(equalTo: of.leftAnchor, constant: margin)
left.identifier = Constraint.left.rawValue
NSLayoutConstraint.activate([left])
setNeedsUpdateConstraints()
print(self.constraints) // prints []
}
/* Other functions left out */
func deleteConstraints(_ constraintsToRemove: Constraint...) {
self.removeConstraints(self.constraints.filter({ c in
guard c.identifier != nil else {
return false
}
return constraintsToRemove.contains { constraint in
constraint.rawValue.elementsEqual(c.identifier!)
}
}))
}
}
However, when I am using these extension functions, the constraints do not fully work. When I add the constraints separately without calling the extension functions, it does work !
Here is my current usage of these functions:
func createButton(icon: String, label: String) -> UIView {
let button = TransparentCardView()
button.translatesAutoresizingMaskIntoConstraints = false
let uiImageView = UIImageView(image: UIImage(named: icon))
button.addSubview(uiImageView)
uiImageView.translatesAutoresizingMaskIntoConstraints = false
uiImageView.constraintCenterVertical(to: button) // works
//uiImageView.constraintLeft(toLeft: button,margin: StyleConstants.contentPadding) // this does not work
uiImageView.leftAnchor.constraint(equalTo: button.leftAnchor,constant: StyleConstants.contentPadding).isActive = true // this does
let textView = UILabel()
button.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.constraintCenterVertical(to: button) // works
//textView.constraintLeft(toRight: uiImageView,margin: 0) // This does not work!
textView.leftAnchor.constraint(equalTo: uiImageView.rightAnchor,constant: StyleConstants.contentPadding).isActive = true // this does work!
button.heightAnchor.constraint(equalToConstant: StyleConstants.More.CardViewSize).isActive = true
return button
}
Edit: I have added additional print calls, after removing previous constraint and after activating the new constraint.
Constraints are printed as []
if I use my extension functions.
but not if i constraint them normally.
I now know why Constraints disappear:
The identifier needs to be unique in the whole View Hierarchy it seems.
After procedurally generating identifier names, constraints do not disappear anymore.
func createConstraintName(constraint:Constraint, from: UIView, to: UIView) -> String {
var symbol = ""
switch (constraint) {
case .bottom: symbol = "___"
case .centerX: symbol = "-X-"
case .centerY: symbol = "-Y-"
case .left: symbol = "|__"
case .right: symbol = "__|"
case .top: symbol = "‾‾‾"
}
return String(describing: from) + symbol + String(describing: to)
}