Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy IB Created Constraints to another UIView

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.

Screenshot

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 ?

like image 300
atastrophic Avatar asked Oct 18 '14 12:10

atastrophic


2 Answers

No quick way.

I've done it with a loop over superview constraints.

Objective-C

+ (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]];
        }
    }
}

Swift

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))
        }
    }
}

Note

Remember to only copy constraints after adding destView to the view hierarchy.

like image 138
Cœur Avatar answered Nov 19 '22 01:11

Cœur


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.

like image 42
algal Avatar answered Nov 19 '22 01:11

algal