iOS 12 wrong navigation bar height - ios

I'm working on an iPad app in landscape orientation. There is a navigation bar at the top without a status bar, and I want to line up a UITableView such that the top of the table is at the same y coordinate as the bottom of the navigation bar. Naturally, I do the following in viewDidLoad:
MyTableView* table = [[MyTableView alloc] init];
table.frame = CGRectMake(someX, navBar.frame.size.height, someWidth, someHeight);
[self.view addSubview:table];
At this point, navBar.frame.size.height returns 44. This is strange, because when I run the app, I see that my table overlaps the bottom of the navigation bar by a few points. I do some investigation, and find out that the navigation bar is actually drawing with a height of 50 points.
I try to think what could be wrong, and realize that perhaps I'm doing this too early in the view controller's lifecycle and the views haven't yet been laid out, so I override viewWillAppear, viewDidAppear, and viewDidLayoutSubviews, all of which report that the navigation bar's height is 44, even when it is clearly drawing with a height of 50.
I thought perhaps there's something I simply don't know, so I setup a timer to run a block of code that would repeatedly print out the height of the navigation bar every second after viewDidLoad was called, which allows for any view controller behind-the-scenes setup to finish. Still, every time the timer triggers the print, the height is only 44.
I took a look at interface builder, and even there, in the dimensions property window (second tab from right), it says the navigation bar has a height of 44. Yet on the screen in the view controller in interface builder, it is clearly drawing with a height of 50.
My question is: why does the reported height not match the height the navigation bar draws at? I need the correct height to place my table in the right location.
At this point I'm at a loss for what could possibly be the issue, save for the API simply being completely broken. The only solution I can think of is to just position the navigation bar at -3 and hardcode in a y value for my table view of 44, resulting in 3 points on the top and bottom of the navigation bar being covered up, which is super janky and I want to avoid it if at all possible.
Now, I understand that autolayout is a thing and constraints exist, but I like to manually compute the frames of my views in code and never use constraints, and that is the realm that this question is in. Please don't give answers like "you're supposed to use constraints".
Although I doubt it matters, I'm running iOS 12.0.1 on an iPad Air 2.
My debugging:
Below is an image of the top center portion of my screen. Each of the rectangles is simply a UIView with a background color set, a y coordinate of 0, a width of 50 points, and are spaced 50 points apart from each other (each starts where the previous one ends). The heights of each rectangle from left to right are: 44, 50, and 51. You can tell the navigation bar is drawing at a height of 50 points since the right rectangle is just barely taller than the navigation bar.
EDIT:
I should probably mention that this navigation bar is added to the view controller via being dragged and dropped into a view controller in the storyboard. I still do some frame shenanigans in viewDidLoad, but it's not being dynamically added to the view there.
Another interesting thing of note: In interface builder, you know the dashed blue lines that help you line things up? Apparently, those align with the 44 point height instead of the 50 point height:

After too much time spent with no progress, I decided to finally bite the bullet and transition to constraints. After I spent far too much time trying to get them to do what I wanted (and failing), it turns out that manually laying out my views wasn't the issue. During the conversion process, I deleted my navigation bar and re-added it to the view controller, which caused everything to start working perfectly. The dashed blue alignment guides lined up with the 50 point height and the height field now always returns 50.
My guess is that the logic in Xcode to upgrade storyboards from pre iOS 12 navigation bars (44 points high) to the new iOS 12 navigation bars (50 points high) is broken, which put my storyboard into a bad state where it thought the height was 44 in some places and 50 in others. Deleting and re-adding it looks to have cleared any record of 44-ness so everything is now properly 50 points high.

Related

How to place any view below any other view which is getting it's position from code

I've created 4 subviews of white color & a yellow one as you can see in reference image I've shared below.
And I've programmatically changed the position of Tabbar from bottom to top just below to navigation bar as you can see in below image (When it is running in the simulator).
Now since I've constraints for that yellow view in image as follow
It is appearing just below to navigation bar but I want it to be displayed just below the Tabbar.
Since Tabbar is getting its position programmatically & other views (including yellow view) are getting their positions from the storyboard.
And since storyboard UIelements are get settled before any other UIelement which are coming from the program or at least get their position from programmatically.
What could be the best way to achieve what I want.
Please refer my storyboard as well to get more understanding. (Refer Below image)
I also want to fit all 5 subviews in the space between tabbar & bottom of the screen. I want to calculate 1/5th of that space & assign this height to each subview. I'd later reduce few pixels to separate them.
Why not add the height of the tab bar to the yellow view's top position? That way, you'd set the constraint something like:
Fajar.top = top + 44
If the tab bar is always visible, then that should work. But of course, if the tab bar only appears at times, you'd probably have to change that constraint programmatically depending on the change ...

Title text hugging/kerning + clipping in UITabBarItem

I have a UITabBarController like this:
As you can see, the 'Discover' and 'Requests' titles are compressed by high amounts of kerning. They are also slightly clipped at the end of each item title. Is there any way to fix this?
P.S. The problem does not appear on iPhone 6 and 6+, only 5S and below.
It seems like there is an issue with UITabBars where, if they deem their frame too small, they'll attempt to kern the item title labels to fit.
This issue with frame size can happen either from manually setting the frame of the UITabBar or possibly by having a larger number of items than will comfortably fit on screen (in your case 5).
In my experience with this issue, someone had erroneously set the frame of the UITabBar to CGRectZero so that, while hidden, it wouldn't effect layout geometry for a UIToolbar. Might you be manually editing the frame of one of the two tab bars you have?
I had this issue happen when I was trying to add a UITabBarController too soon. I was adding it as a child view controller of the main window.rootViewController in its viewDidLoad: method. However, the root view has not been properly initialized at this point yet, so the tab bar was using incorrect frame for calculations (as Ben Lachman alluded to). I solved it by adding a delay to initialize the images on the tab bar items, which in turn made the titles display with correct spacing.

Applying bar metrics on a standalone UINavigationBar

My app has a view controller that due to the fact it plays its own custom transition animations, provides its own standalone UINavigationBar view at the top (As opposed to using a UINavigationController).
When using an iPhone, and when rotating the device, I would like the UINavigationBar to automatically apply the landscape UIBarMetrics properties (eg, change height, change the background image, resize the buttons etc), but by default, it does not. This is a problem on iOS 7, since even if I manually change the height of the UINavigationBar, the UIBarButtonItem elements don't change their vertical positions.
Is there a way to manually 'tell' the UINavigationBar to apply specific bar metric properties to itself? Or is that actually an implementation inside UINavigationController, and not UINavigationBar?
After various testing and trial and error after asking this question, I eventually worked out a solution that fixed all of my issues, so I'll post it here under the solution I'd previously accepted.
When my app is displayed in landscape on an iPhone, I wanted the UINavigationBar at the top to shrink to the standardly accepted 32 points high, as is the case with any apps that use the UINavigationController class. However, as I am not using a UINavigationController for this particular view (for varying reasons of feasibility), I needed to implement this manually.
To account for the new transparent status bar in iOS 7, I adjusted the origin and size of the UINavigationBar so it encompassed both the bounds of the status bar, and the normal UINavigationBar region (ie, so the UINavigationBar frame origin was {0,0}, and the height was 52 points.)
Unfortunately, this happened:
While the bar itself is rendering at the proper position and height, all of the content in the bar, including the title and buttons are not positioned properly, being much too high, almost touching the status bar content.
It was pretty obvious what was happening. The navigation bar content is being vertically aligned to its own middle, completely disregarding the presence of the status bar content.
When I tested the same orientations with a normal UINavigationController, this was not the case, and the title and buttons in the UINavigationBar from the UINavigationController worked absolutely fine. Apple had done SOMETHING in there that wasn't part of the normal UINavigationBar implementation.
Going on this, I picked apart the view layout hierarchy of a UINavigationControllerto see what was happening to the UINavigationBar in there (Mainly calling a lot of NSLog() statements that would dump the subviews of the navigation bar.)
This is what I discovered:
From the looks of it, Apple have employed a relatively sneaky hack to achieve this effect. It turns out the actual UINavigationBar is actually placed right below the status bar (ie at point {0,20}) and only has a height of 32 points. Then, what happens is a private subview inside the UINavigationBar in charge of rendering the background is extended upwards, outside of the bounds of the navigation bar to encompass the region behind the status bar (ie, its origin is {0, -20}, and its height is 52 points, local to the navigation bar's subview coordinate space).
So by doing that, not only does the content vertically align properly, but the translucent effect still extends behind the status bar.
Anyway, after I discovered this, it was pretty straightforward to write a solution. All I needed to do was reposition and resize the UINavigationBar back to how I had it iOS 6 (ie, 20 points down, and only 32 points high), and then implement a UINavigationBar subclass that override the layoutSubviews method, grabbed the internal background view (Doing a quick subview check for a view with a class name that matched "Background"), and then manually extended it.
The bar metrics properties you can set on a UINavigation bar are things like background image and the title vertical position. Heigh and width need to be set from within your view controller.
If you need to manually tell the navigation bar to change it's size when the orientation changes you can implement the method - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration1 in your view controller and change the size there.
Another option you can use is to use autolayout to specify that the width of your navigation bar is pinned to the left and right sides of its superview and let it figure out how wide it should be. For example
UINavigationBar *bar = [[UINavigationBar alloc] init];
bar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:bar];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[bar]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(bar)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[bar(44)]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(bar)]];

Any quick solution to make a view appear behind the status bar in iOS 7?

I'm porting my app from iOS 6 to IOS 7 (there will eventually be a complete GUI redesign for iOS 7 but in the meanwhile just getting the existing GUI to display properly on iOS 7 is the goal.
I had the issue where the status bar was overlapping my GUI and so have shifted the Y origin of the view controller's view down by 20.
However my app contains a pulldown which when retracted is overlapping with the status bar. In the screenshot the red is a button which is present in the pulldown view. The grey bar is the top of the main view behind which a portion of pulldown is hiding when retracted.
I implemented the pull down as a fixed size child subview of the main view and when retracted its Y origin is a negative number thus it is effectively still displayed but off the top of the screen. When the user pulls it down I just animate the increase in the Y origin until eventually the origin is 0.
Is there some way I can make the pull down view appear beneath the status bar or some other quick solution?
Note of course I can't simply toggle the pulldown's alpha to display/hide it as it pullsdown obviously thus its appearance/disappearance is not a discreen action. I could maybe attempt to make the portion of it that is on top of the status bar invisible but as its something that is moving that seems like its going to be complicated. Is there any simple solution?
Thanks
Add another view, with a fixed position, under the status bar (with the same color of your grey bar), 20px tall and same width of the status bar, but with a z-index higher than the retracting view. This view will cover the retracting view (but not the status bar) acting as a "background" for the status bar itself. Obviously you have to adjust the Y position of the retracting view to make it tappable by the user (but under the status bar)
iOS 7 by default lets views take up the fullscreen, including the status bar. This is controlled using the UIRectEdgeAll property.
If you want the old style view, set UIRectEdgeNone for self.edgesForExtendedLayout
in viewDidLoad:
self.edgesForExtendedLayout = UIRectEdgeNone;

GLKView frame size animation causes GL to render only a portion of the screen

I have a GLKView contained in a UIView under a top, nav-like bar. The bar can be shown/hidden with an animation and the autolayout pinning causes the views to fill the portion of the screen under the bar (or the full screen if hidden).
What's odd is that when the top bar begins its show/hide animation, the GLKView immediately jumps to the final height. When showing the top bar (which shrinks the GLKView), it causes clear band to be seen on the top and bottom.
What's also odd is that the view's position seems to work correctly, and animates smoothly down as the top bar comes down until they all eventually line up as they should.
Dumping out out the GLKView's layer.presentationLayer property seems to indicate that it's bounds animates correctly.
The GLK-ness of the view could be a red-herring as I haven't tested this on other parts of the app...will do though...
Very confused. Sorry no photos but it's all NDA and I've no time to make a sample project right now. Maybe later if need be. Thanks...

Resources