8

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

5
  • Can you show some code? Commented Jan 16, 2015 at 2:26
  • Which method do you invoke this code from? viewDidAppear? viewDidAppear? or some other method? Commented Jan 16, 2015 at 3:18
  • Just added another edit. It triggers from the tap on the screen using animation block. Commented Jan 16, 2015 at 3:41
  • I can't see the problem from what you have shown here. You may need to set a breakpoint, but I was going to suggest what Charlie Wu just put in his answer - modify the existing constraints if you can - much easier Commented Jan 16, 2015 at 3:56
  • Thank you anyway for the advice. It looks like it's no good to mix up IB and hardcode approach. Commented Jan 16, 2015 at 15:57

2 Answers 2

23

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

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the answer, that definitely would work. But what if I had a lot of constraints to adit? I need views to appear and disappear, change their places on screen and so on. I think if I create outlet for each constraint - view controller implementation would be a horrible mess
if you are using code, wouldn't you have tone of code loop through view constrains and look for the correct one? it's much harder to maintain when view layout is changed. This one it might not be the cleanest code, but it should be fairly easy to maintain and understand
2

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.

2 Comments

Thank you for the advice! It works perfectly fine. But the reason why I tried to do it programmatically is that I have a lot of views to change constraints. At some point I need all views to disappear from the screen and display new ones - datePicker, in particular and several custom controls. And than it should return to previous state. What would you do in that kind of situation? Thanks again!
I keep an array of changing constraints when setting the view and since you can only change the constant anyways. I subclass the UIVIew and works fine for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.