Reputation: 81
I have 2 buttons with different constraints write in the storyboard. In my code, I have to tell my first button to take the same constraint of the second button (height, width, and position) but I do not know how to do this without necessarily passing by "subview". I have 2 outlets for my buttons.
@IBOutlet weak var likesButton: UIButton!
@IBOutlet weak var shareButton: UIButton!
My interface is build like that :
-
VIEW
a)...View
b)...View
c) ContentView
1)likeButton
2)shareButton
3)...
d)...
I tried like this :
self.contentView.translatesAutoresizingMaskIntoConstraints = false
self.shareButton.removeConstraints(self.shareButton.constraints) // Old Constraints
self.shareButton.addConstraints(self.likeButton.constraints) // New Constraints
self.shareButton.updateConstraintsIfNeeded()
self.shareButton.layoutIfNeeded()
And after I have this error :
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint:<NSLayoutConstraint:0x14cfe7600 H:[UIButton:0x14cfb7bd0(40)]> view:<UIButton: 0x14e30fa60; frame = (494 528; 26 31); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x14e30f410>>'
Thx in advance.
Upvotes: 0
Views: 1147
Reputation:
If this is your scenario:
Then you can set up an IBOutlet for each constraint and do your editing (changing, replacing, or even deactivating them) by name.
@IBOutlet weak var likesConstraintLeading: NSLayoutConstraint!
@IBOutlet weak var likesConstraintTop: NSLayoutConstraint!
@IBOutlet weak var likesConstraintWidth: NSLayoutConstraint!
likesConstraintLeading.isActive = false
likesConstraintTop.constant = 20
likesConstraintWidth.multiplier = 3.5
You can set up the new set of constraints in code as an array and activate them after removing the old constraints.
@IBOutlet weak var likesConstraintTop: NSLayoutConstraint!
@IBOutlet weak var likesConstraintLeading: NSLayoutConstraint!
@IBOutlet weak var likesConstraintWidth: NSLayoutConstraint!
var newConstraints = [NSLayoutConstraint]()
newConstraints.append(likesButton.leadingAnchor.constraint(equalTo: view.leadingAnchor))
newConstraints.append(likesButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20))
newConstraints.append(likesButton.widthAnchor.constraint(equalToConstant: 100))
likesConstraintLeading.isActive = false
likesConstraintTop.isActive = false
likesConstraintWidth.isActive = false
NSLayoutConstraint.activate([newConstraints])
Please note - you still need to deactivate things one-by-one because these constraints (except for the width) is added to the control's superview and there are likely many more constraints in it!
This IMHO is the best setup you can do, because you can still add all of your other constraints through IB and limit your code to what you wish to change.
var startingConstraints = [NSLayoutConstraint]()
var endingConstraints = [NSLayoutConstraint]()
override func viewDidLoad() {
startingConstraints.append(likesButton.leadingAnchor.constraint(equalTo: view.leadingAnchor))
startingConstraints.append(likesButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20))
startingConstraints.append(likesButton.widthAnchor.constraint(equalToConstant: 100))
endingConstraints.append(likesButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30))
endingConstraints.append(likesButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 40))
endingConstraints.append(likesButton.widthAnchor.constraint(equalToConstant: 80))
NSLayoutConstraint.activate([startingConstraints])
}
func changeConstraints() {
NSLayoutConstraint.deactivate([newConstraints])
NSLayoutConstraint.activate([newConstraints])
}
Upvotes: 1
Reputation: 11928
Does the constraint reference something from outside the subtree of the view?
This is as if it said...
Does the constraints of likeButton reference something from outside the subtree of the shareButton?
So, the likeButton constraint references (like the likeButton itself) are completely outside the shareButtons view hierarchy. They can't be added this way.
You could instead do:
self.view.removeConstraints(self.shareButton.constraints)
self.view.addConstraints(self.likeButton.constraints)
But this won't accomplish whatever you're trying to do.
A constraint is more than just a number and dimension. It also defines which two objects are constrained. So trying to map one views constraints to another like that won't work because it doesn't change which views are referenced in the constraint.
You can probably hack out a way to do it using outlets to the various constraints and pulling the constraint constants out of one view and assigning them to the other.
Upvotes: 1