When to update constraints with AutoLayout in iOS 7

10,424

Solution 1

When using Autolayout you shouldn't be setting the view's frame. Instead you should adjust the constraints, usually the 'constant' property.

In your case, you are changing the height of a view and in the process breaking a constraint.

Solution 2

Note sure if I understood exactly your problem, but the scroll view is pretty special in regards to autolayout (see technote https://developer.apple.com/library/ios/technotes/tn2154/)

Share:
10,424
Martin de Keijzer
Author by

Martin de Keijzer

Martin is a software engineer at Spinnin' Records in The Netherlands. With over 10 years of experience in web development his focus is mainly on new technologies and working on quality control. Martin is also a board member of the PHPBenelux user group.

Updated on June 14, 2022

Comments

  • Martin de Keijzer
    Martin de Keijzer almost 2 years

    In my application I want to resize a UITextView (self.message), Navigation Controller's view and I want to change the position of a UIScrollView (self.selectedMedia) when the keyboard shows. To accomplish that I'm using this delegate method:

    - (void)keyboardWillShow:(NSNotification *)notification
    {
    NSDictionary* userInfo = [notification userInfo];
    
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrame;
    CGRect navigationControllerFrame = self.navigationController.view.frame;
    CGRect textViewFrame = self.message.frame;
    CGFloat keyboardHeight;
    
    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame];
    
    keyboardHeight = keyboardFrame.size.height;
    
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];
    [UIView setAnimationCurve:animationCurve];
    
    [self.navigationController.view setFrame:CGRectMake(
                                                        navigationControllerFrame.origin.x,
                                                        navigationControllerFrame.origin.y,
                                                        navigationControllerFrame.size.width,
                                                        navigationControllerFrame.size.height - keyboardHeight
                                                        )];
    [self.message setFrame:CGRectMake(
                                      textViewFrame.origin.x,
                                      textViewFrame.origin.y,
                                      textViewFrame.size.width,
                                      textViewFrame.size.height - keyboardHeight)];
    
    if (self.selectedMedia.hidden == NO) {
        [self.selectedMedia setFrame:CGRectMake(
                                                self.selectedMedia.frame.origin.x,
                                                self.selectedMedia.frame.origin.y - keyboardHeight,
                                                self.selectedMedia.frame.size.width,
                                                self.selectedMedia.frame.size.height
                                                )];
    }
    
    [self.navigationController.view updateConstraints];
    [UIView commitAnimations];
    }
    

    When I run this code, I get an error that the constraints cannot be satisfied:

    2013-10-11 14:03:52.532 PoC[78199:a0b] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
    (
    "<NSLayoutConstraint:0xe5502d0 V:[UITextView:0xf26da00(380)]>",
    "<NSLayoutConstraint:0x8b93620 V:|-(0)-[UITextView:0xf26da00]   (Names: '|':UIView:0x8b978f0 )>",
    "<NSLayoutConstraint:0x8b984c0 V:[UIScrollView:0x8b8f570]-(0)-|   (Names: '|':UIView:0x8b978f0 )>",
    "<NSLayoutConstraint:0x8b98520 V:[UITextView:0xf26da00]-(0)-[UIScrollView:0x8b8f570]>",
    "<NSAutoresizingMaskLayoutConstraint:0x8b9acf0 h=--& v=--& V:[UIView:0x8b978f0(244)]>"
    )
    
    Will attempt to recover by breaking constraint 
    <NSLayoutConstraint:0xe5502d0 V:[UITextView:0xf26da00(380)]>
    

    I wonder why the UITextView still has a height of 380. Doesn't the statement [self.navigationController updateConstraints] adjust the height based on the given constraints? Should the constraints be updated after committing the animation? Or is there something else I'm overlooking?