Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS7 - View under status bar - edgesForExtendedLayout not working

I have a project that was built last year, and it uses XIBs, no storyboards. The XIBs do not use Auto Layout, but they do use some Autosizing. I have an issue when running with iOS7, in which all the views are tucked under the status bar. I fully understand this is a new feature with iOS7, in which this can be expected. However, all of the solutions for fixing it to not do this are not working. I have an image at the top of the view that always shows under the status-bar, and I'm not using nav-bars or anything like that.

I have tried updating the Y-deltas in the XIB (they have no effect on the view), I have tried setting the edgesForExtendedLayout to UIRectEdgeNone (does nothing), and a multitude of other things. Every time, the status bar shows with the view tucked under it, no matter what I do.. that is unless I manually move down the view in the XIB to allow room for the status bar (but that solution doesn't work because it doesn't look right in iOS6, of course).

What's odd is that even when I try a line of code to hack in a view-shift, it doesn't work (like the following):

self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+20, self.view.frame.size.width, self.view.frame.size.height);

..Not that I would go with that kind of solution, but it's just odd that it didn't work (the only time I typically see that not work is if Auto Layout is in place, which it's not in this case).

It is a design requirement that the status-bar shows, and I'm just stumped on why I can't set the view to be under the status bar for iOS7. I have read every single Stack Overflow post on the subject, as well as Apple's transition/guides. Once again, to reiterate, I fully understand how it should function and what the expected solution should be to this, but none of that seems to be working for this particular project.

I am an experienced iOS dev, but this project was built by another team, so I don't know if there's something hidden somewhere in the XIB files, plist, or code that could be trumping the above settings. Please let me know if there is something else that can be looked at on this, or more information I can provide.

Thanks in advance!

like image 979
svguerin3 Avatar asked Sep 24 '13 19:09

svguerin3


3 Answers

If you set the iOS 6/7 delta values in Interface Builder, remember to set "View as" to "iOS 6" on the Interface Builder Document, since it is the iOS 6 layout you want to replicate. The deltas will then be used only on iOS 7 to push the content below the status bar. If you leave "View as" set to iOS 7 (the default) the deltas will instead give you the iOS 7 look on iOS 6.

However, the deltas will not help you if you reposition or resize views programmatically based on the view frame, since the frame does not account for the deltas.

Instead of using the deltas, the best solution I have found is to enable Auto Layout on your main XIB and then set the top space constraint on your top/content view to follow the Top Layout Guide. This guide was introduced in iOS 7 and represents the position below the status bar. Unfortunately the guide is not available in Interface Builder when not using Storyboards, but you can add it programmatically.

What I did was add a top space constraint to the superview instead in Interface Builder, and created an outlet for this in the code. Then, in viewDidLoad, if the topLayoutGuide is available (iOS 7+), replace the constraint in this outlet with a version using the Top Layout Guide instead.

if ([self respondsToSelector:@selector(topLayoutGuide)]) {     [self.view removeConstraint:self.containerTopSpaceConstraint];      self.containerTopSpaceConstraint =     [NSLayoutConstraint constraintWithItem:self.contentView                                  attribute:NSLayoutAttributeTop                                  relatedBy:NSLayoutRelationEqual                                     toItem:self.topLayoutGuide                                  attribute:NSLayoutAttributeBottom                                 multiplier:1                                   constant:0];      [self.view addConstraint:self.containerTopSpaceConstraint];      [self.view setNeedsUpdateConstraints];     [self.view layoutIfNeeded]; } 
like image 77
Kim Avatar answered Nov 14 '22 03:11

Kim


For reference, the solution below did work when I applied it to my ViewControllers. However, it's not ideal and a bit hacky. If it's the only approach I can take, then so be it, though.

float systemVersion=[[[UIDevice currentDevice] systemVersion] floatValue];
if(systemVersion>=7.0f)
{
    CGRect tempRect;
    for(UIView *sub in [[self view] subviews])
    {
        tempRect = [sub frame];
        tempRect.origin.y += 20.0f; //Height of status bar
        [sub setFrame:tempRect];
    }
}
like image 33
svguerin3 Avatar answered Nov 14 '22 04:11

svguerin3


Apple are pushing you to use autolayout to accomplish this. You need to set a constraint to the "Top Layout Guide" from the top subview in your view.

See this document for examples:

https://developer.apple.com/library/ios/qa/qa1797/_index.html

To do this without XIBs, you'll need to add the constraint programatically. Apple's docs give a good example of this, which I've summarised below.

Giving that the topLayoutGuide is a property on a view controller, you just use it in your dictionary of variable bindings. Then you set up your constraint like normal:

id topGuide = [myViewController topLayoutGuide];
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(button, topGuide);
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide]-20-[button]" options:0 metrics:nil views:viewsDictionary]; 

The documentation for this can be found in the UIViewController class reference.

like image 26
petehare Avatar answered Nov 14 '22 05:11

petehare