I have a simple layout where I have a UINavigationViewController
and a regular view controller displaying inside of it. I then have an image of fixed size, and some text that is supposed to fill the remaining space. See below:
The top of the image in the foreground is constrained to the top layout guide, which works fine in Xcode (doesn't show any warnings or anything), but at run time seems to be ignored:
The top of the image is anchored to the top of the screen instead of the bottom of the navigation bar. I understand that this is not necessarily incorrect (table views scrolling up below the navigation bar), but this is super annoying because there's no scrolling involved here.
But wait, there's more. If I rotate the screen, it fixes itself!
I tried stuff like adding a call to layoutIfNeeded
in different places, to no avail.
What am I doing wrong?
Side notes:
- I tested it on device, and it behaves identically, so I only screenshotted the simulator
- Ignore the background image view, it is not relevant
- I don't know why the text displays cut off in Xcode, but it seems to work fine at runtime so I don't care
Per dasdom's comment below, I have tried adding this constraint in code, with no apparent change. I'm not 100% certain that I got it right, though:
-(void)viewDidLayoutSubviews {
NSMutableDictionary * views = [NSMutableDictionary new];
views[@"v"] = self.imageView;
views[@"topLayoutGuide"] = self.topLayoutGuide;
NSMutableArray * constraints = [NSMutableArray new];
[constraints addObjectsFromArray:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[topLayoutGuide][v]"
options:0
metrics:nil
views:views]
];
[self.view addConstraints:constraints];
[self.view layoutSubviews];
}
A few debugging outputs:
If I print out the navigation controller during viewWillAppear
, I get this:
2014-05-21 14:45:51.961 iBeaconMap[914:60b] self.navigationController.navigationBar: <UINavigationBar: 0x8cbded0; frame = (0 20; 320 44); opaque = NO; autoresize = W; userInteractionEnabled = NO; gestureRecognizers = <NSArray: 0x8c72440>; layer = <CALayer: 0x8cbe010>>
If I set a timer to print out the value of topLayoutGuide
at regular intervals, it says "20" until the first time I rotate, at which point it says "52" or "64" depending on orientation (as expected).
Maybe I need to figure out what the rotation is doing to the navigation controller, and simulate that....... is grasping at straws