1

I have some auto layout code that is working in iOS 7, but not in iOS 8. My code has not changed between the two versions.

The situation is that I have a view controller that contains a few subviews that should be stacked vertically like so:

iOS 7 layout

However, when I run the same code on iOS 8, the following occurs:

iOS 8 layout

The code that sets up my constraints is as follows:

- (void) updateViewConstraints {
    [super updateViewConstraints];

    NSDictionary *viewsDictionary = @{
        @"timeLabel": self.timeLabel,
        @"recordingStateImage": self.recordingStateImage,
        @"recordButton": self.recordButton,
        @"spacer1": spacer1,
        @"spacer2": spacer2,
        @"superview": self.view
    };

    if (!portraitConstraints) {
        //
        // Portrait Layout
        //

        portraitConstraints = [[NSMutableArray alloc] initWithArray:
            [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[timeLabel][spacer1][recordingStateImage][spacer2(==spacer1)][recordButton(100)]-|"
                                                    options:0
                                                    metrics:0
                                                      views:viewsDictionary]];

        [portraitConstraints addObjectsFromArray:@[
            [NSLayoutConstraint constraintWithItem:self.timeLabel
                                         attribute:NSLayoutAttributeCenterX
                                         relatedBy:NSLayoutRelationEqual
                                            toItem:self.view
                                         attribute:NSLayoutAttributeCenterX
                                        multiplier:1.f
                                          constant:0.f],
            [NSLayoutConstraint constraintWithItem:self.recordingStateImage
                                         attribute:NSLayoutAttributeCenterX
                                         relatedBy:NSLayoutRelationEqual
                                            toItem:self.view
                                         attribute:NSLayoutAttributeCenterX
                                        multiplier:1.f
                                          constant:0.f],
            [NSLayoutConstraint constraintWithItem:self.recordButton
                                         attribute:NSLayoutAttributeCenterX
                                         relatedBy:NSLayoutRelationEqual
                                            toItem:self.view
                                         attribute:NSLayoutAttributeCenterX
                                        multiplier:1.f
                                          constant:0.f]
        ]];
    }

    [self.view removeConstraints:self.view.constraints];
    [self.view addConstraints:portraitConstraints];

}

I am not sure why this is happening. I have examined the workaround noted in the following SO questions:

but they have not worked (which is calling setNeedsLayout on the subviews instead of the view controller's view).

If anyone has hit issues w/ NSLayoutAttributeCenterX and auto layout on iOS 8, it would be much appreciated.

Community
  • 1
  • 1
linusthe3rd
  • 3,455
  • 3
  • 28
  • 43

3 Answers3

2

As my comment help to solve problem and OP need more information about the same issue i post comment as an answer


Note :
It's bad practice to remove all constraints as it will remove all constraint added by XCode to fit your view properly in device.

Having different UI in landscape and portrait mode
If your view having different constraint in landscape and portrait (In compact and regular view).
you can use size classes introduce in XCode6 with backward comparability.

Please follow this blog explaining size class very nicely.
download project create in above blog.

Output:
View in landscape mode enter image description here

View in portrait mode: enter image description here

Jageen
  • 6,345
  • 2
  • 37
  • 56
  • jw - do you have any thoughts on making this stuff backwards compatible? What I ended up doing was keep my old logic in ```updateConstraints```, but only run it when the OS is < iOS 8. – linusthe3rd Dec 05 '14 at 15:31
  • according to apple size clasess are backward compatible https://developer.apple.com/library/ios/recipes/xcode_help-IB_adaptive_sizes/chapters/DeployingSizeClassesonEarlieriOSVersions.html#//apple_ref/doc/uid/TP40014436-CH13-SW1 – Jageen Dec 05 '14 at 15:43
  • I did not try but this question my help http://stackoverflow.com/questions/24172860/how-can-xcode-6-adaptive-uis-be-backwards-compatible-with-ios-7-and-ios-6 – Jageen Dec 05 '14 at 15:44
0

It turns out that iOS 8 and Xcode 6 adds extra constraints to the view to help lay out its elements. I figured this out by Jageen above and in a comment on a github issue.

The solution to the problem is to not call [self.view removeConstraints] in iOS 8 as it will remove these extra, required constraints. My personal workaround to this is to utilize nibs for iOS 8 w/ its orientation-specific constraints and do an OS check to only run the above code in versions <= to iOS 7.

If anyone has a backwards-compatible workaround to this issue w/ calling removeConstraints on a view, I would be very interested in seeing it (as I have a different layout for portrait vs. landscape).

Community
  • 1
  • 1
linusthe3rd
  • 3,455
  • 3
  • 28
  • 43
  • As you have different layout for portrait and landscape you can use size class (introduce in XCode6 with backward comparability), have look at this example http://www.raywenderlich.com/83276/beginning-adaptive-layout-tutorial – Jageen Dec 05 '14 at 05:07
0

I had this problem. In my case its cause was the line

self.view.translatesAutoresizingMaskIntoConstraints = NO; (self is UIViewController)

After setting the constraint I typed po self.view.layer during a breakpoint into the console and it appeared fine. I was setting the constraint in viewDidLoad (experimenting with viewWillAppear and viewWillLayoutSubviews yields the same result). However, when I added a breakpoint in viewDidAppear and typed the same command in the console the width and height of self.view had both changed to zero. I removed the above line and it worked. self.view retained its height and width and the subview aligned in the center.

Andrew McKinley
  • 1,137
  • 1
  • 6
  • 11