I have UITableView
listing along with other view elements on a screen. I plan to swap out this listing with another view when there are no transactions to display. For this I need to copy all the constraints attached to UITableView
and add them to new UIView
.
I have tried copying .constraints()
property values but it returns nil because constraints are attached to superview. Getting constraints from superview
yields all constraints attached to other subviews as well.
Is there a quick way of copying and adding constraints from one UIView
to another ?
No quick way.
I've done it with a loop over superview constraints.
+ (void)copyConstraintsFromView:(UIView *)sourceView toView:(UIView *)destView
{
for (NSLayoutConstraint *constraint in sourceView.superview.constraints) {
if (constraint.firstItem == sourceView)
{
[sourceView.superview addConstraint:[NSLayoutConstraint constraintWithItem:destView attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:constraint.secondItem attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant]];
}
else if (constraint.secondItem == sourceView)
{
[sourceView.superview addConstraint:[NSLayoutConstraint constraintWithItem:constraint.firstItem attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:destView attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant]];
}
}
}
static func copyConstraints(fromView sourceView: UIView, toView destView: UIView) {
guard let sourceViewSuperview = sourceView.superview else {
return
}
for constraint in sourceViewSuperview.constraints {
if constraint.firstItem as? UIView == sourceView {
sourceViewSuperview.addConstraint(NSLayoutConstraint(item: destView, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: constraint.secondItem, attribute: constraint.secondAttribute, multiplier: constraint.multiplier, constant: constraint.constant))
} else if constraint.secondItem as? UIView == sourceView {
sourceViewSuperview.addConstraint(NSLayoutConstraint(item: constraint.firstItem, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: destView, attribute: constraint.secondAttribute, multiplier: constraint.multiplier, constant: constraint.constant))
}
}
}
Remember to only copy constraints after adding destView to the view hierarchy.
No, there's nothing built into the system for this.
The NSLayoutConstraint
object is immutable except for its constant
priority, so once the object is created you cannot simply apply the "same" constraint to another view (where "same" means either object identity or object equality).
If performance allows, rather than setting up and tearing down views with all their constraints, I'd just setup both the table view and the no-data counterpart views as siblings, using one helper function to install equivalent constraints on each, so that they are laid out identically, but with one atop the other. Then I'd just swap which view is visible with the hidden
property.
However, if you really want to duplicate one view's constraints onto another view, at runtime, in a general way, you'll have to write a utility method that does a recursive search starting from the most ancestral superview which might have any constraint affecting the view-being-copied, and creates a duplicate constraint applied to the other view. Such a function might already be written in one of the AL helper libraries, like FLKAutoLayout.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With