简体   繁体   中英

iOS: programmatically changing constraints set from Interface Builder

Good day, friends!

I failed trying to animate views that were set in IB from code. App crashes with following reason:

The view hierarchy is not prepared for the constraint...

I saw some similar questions here and the reason was always that the view which was created programmatically, is not yet added to superview. But I created all views in IB!

The console also says:

View not found in container hierarchy: (here goes it's superview)

It doesn't make any sense to me because in fact it is a subview of appropriate superview, and xcode knows it - it prints view hierarchy right away and it fits.

What could the reason? Thank you!

Edit: code I use:

    - (void)setEditingConstraintsForView:(UIView *)view
{
    // Pin given view to top, fix it height
    NSDictionary *givenView = @{@"view":view};
    view.translatesAutoresizingMaskIntoConstraints = NO;

    NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:givenView];
    NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view(height)]" options:0 metrics:@{@"height":@(viewHeight)} views:givenView];

    [self.animatedVIew addSubview:view];

    for (NSArray *constraints in @[horizontalConstraints, verticalConstraints]) {
        [view addConstraints:constraints];
    }
}

Also I delete all constraints that I set in IB before installing new:

    - (NSDictionary *)constraintsFromIB
{
    if (!_constraintsFromIB) {
        _constraintsFromIB = @{@"view1":self.view1.referencingConstraintsInSuperviews,
                               @"view2":self.view2.referencingConstraintsInSuperviews,
                               @"view3":self.view3.referencingConstraintsInSuperviews };
    }

    return _constraintsFromIB;
}

And then:

- (void)updateViewConstraints
{
    [super updateViewConstraints];

    // clear all constraints
    for (NSString *viewName in self.constraintsFromIB.allKeys) {
        for (NSLayoutConstraint *constraint in self.constraintsFromIB[viewName]) {
            [constraint remove];
           }

} }

UPDATE 2: Method I use invoke change: when user touches the view, this one is called:

- (void)animateConstraintsForState:(LDYEditingLabel)state
{
    self.editingLabel = state;        
    [UIView animateWithDuration:0.3 animations:^{
        [self updateViewConstraints];
        [self.view layoutIfNeeded];
    }];
}

Later in updateViewConstraints: there is a code that triggers my method setEditingConstraintsForView:(UIView *)view

if you use IB to create constrains you can add constrains as outlet.

You then update the constrain and call [self updateViewConstraints]; in the animation block

在此输入图像描述

If it were me, I'd wire the constraints to IBOutlets and just modify the existing constraints. It would probably end up being easier than adding and removing them programmatically.

You may also need to call setNeedsLayout after you've modified the constraints.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM