In an @IBDesignable
,
I'm trying to programmatically set "width 20% of parent":
@IBDesignable
class TwentyPercentExample:UIView {
func setup() {
let cWidth = NSLayoutConstraint(
item: self,
attribute: NSLayoutAttribute.width,
relatedBy: NSLayoutRelation.equal,
toItem: self.superview,
attribute: NSLayoutAttribute.width,
multiplier: 0.2,
constant:0
)
addConstraint(cWidth)
print("I seemed to added the width constraint....")
updateConstraintsIfNeeded() // could be useful..
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
}
(So, you'd add a UIView in storyboard, perhaps set it anchored on the left to the superview, and then change the class to TwentyPercentExample.)
Strangely this doesn't work. if you do this:
multiplier: 1,
constant:100
it nicely sets it, in realtime, in storyboard to 100 width. Change to
multiplier: 1,
constant:200
and it works fine, changes it in realtime to 200 width. However this just doesn't seem to work:
multiplier: 0.2,
constant:0
Do I have toItem:
wrong, or something? What's the deal?
I suspect the problem is that you're doing this in init
when self.superview
is nil
. You should wait to add the constraint until after its been added to the superview. Perhaps in didMoveToSuperview()
, though this could get messy since you'll need to account for the fact that it could be added to a superview more than once.
Probably the reason the fixed constant case works is because its legal to have a constraint that's hardcoded to 100 with a nil
item as the toItem:
argument.
So, either of these
override func didMoveToSuperview() { setup() }
... or ...
override func layoutSubviews() { setup() }
func setup() {
self.widthAnchor
.constraint(equalTo: superview!.widthAnchor, multiplier: 0.2)
.isActive = true
}
seem to work: but seems to work irregularly and generate "agent crashed" errors in Xcode.