I know that the presence of the more view controller (navigation bar) pushes down the UIView by its height. I also know that this height = 44px. I have also discovered that this push down maintains the [self.view].frame.origin.y = 0.

So how do I determine the height of this navigation bar, other than just setting it to a constant?

Or, shorter version, how do I determine that my UIView is showing with the navigation bar on top?


The light bulb started to come on. Unfortunately, I have not discovered a uniform way to correct the problem, as described below.

I believe that my whole problem centers on my autoresizingMasks. And the reason I have concluded that is the same symptoms exist, with or without a UIWebView. And that symptom is that everything is peachy for Portrait. For Landscape, the bottom-most UIButton pops down behind the TabBar.

For example, on one UIView, I have, from top to bottom:

UIView – both springs set (default case) and no struts

UIScrollView - If I set the two springs, and clear everything else (like the UIView), then the UIButton intrudes on the object immediately above it. If I clear everything, then UIButton is OK, but the stuff at the very top hides behind the StatusBar Setting only the top strut, the UIButton pops down behind the Tab Bar.

UILabel and UIImage next vertically – top strut set, flexible everywhere else

Just to complete the picture for the few that have a UIWebView:

UIWebView - Struts: top, left, right Springs: both

UIButton – nothing set, i.e., flexible everywhere

Although my light bulb is dim, there appears to be hope.


Please bear with me because I needed more room than that provided for a short reply comment.

Thanks for trying to understand what I am really fishing for ... so here goes.

1) Each UIViewController (a TabBar app) has a UIImage, some text and whatever on top. Another common denominator is a UIButton on the bottom. On some of the UIViewControllers I have a UIWebView above the UIButton.

So, UIImage, text etc. UIWebView (on SOME) UIButton

Surrounding all the above is a UIScrollView.

2) For those that have a UIWebView, its autoresizingMask looks like:

   —
   |
   —

   ^
   |
   |

|—| ←----→ |—| | | V The UIButton's mask has nothing set, i.e., flexible everywhere

Within my -viewDidLoad, I call my -repositionSubViews within which I do the following:

If there is no UIWebView, I do nothing except center the UIButton that I placed with IB.

If I do have a UIWebView, then I determine its *content*Height and set its frame to enclose the entire content.

UIScrollView *scrollViewInsideWebView = [[webView_ subviews] lastObject];
webViewContentHeight = scrollViewInsideWebView.contentSize.height;
[webView_ setFrame:CGRectMake(webViewOriginX, webViewOriginY,
                          sameWholeViewScrollerWidth, webViewContentHeight)]

Once I do that, then I programmatically push the UIButton down so that it ends up placed below the UIWebView.

Everything works, until I rotate it from Portrait to Landscape.

I call my -repositionSubViews within my -didRotateFromInterfaceOrientation.

Why does the content height of my UIWebView not change with rotation?.

From Portrait to Landscape, the content width should expand and the content height should shrink. It does visually as it should, but not according to my NSLog.

Anyway, with or without a UIWebView, the button I've talked about moves below the TabBar when in Landscape mode but it will not scroll up to be seen. I see it behind the TabBar when I scroll "vigorously", but then it "falls back" behind the TabBar.

Bottom line, this last is the reason I've asked about the height of the TabBar and the NavigationBar because the TabBar plants itself at the bottom of the UIView and the NavigationBar pushes the UIView down.

Now, I'm going to add a comment or two here because they wouldn't have made sense earlier.

With no UIWebView, I leave everything as is as seen by IB.

With a UIWebView, I increase the UIWebView's frame.height to its contentHeight and also adjust upward the height of the surrounding UIScrollView that surrounds all the sub-views.

Well there you have it.


Do something like this ?

    NSLog(@"Navframe Height=%f",
        self.navigationController.navigationBar.frame.size.height);

The swift version is located here


UPDATE

iOS 13

As the statusBarFrame was deprecated in iOS13 you can use this:

extension UIViewController {

    /**
     *  Height of status bar + navigation bar (if navigation bar exist)
     */

    var topbarHeight: CGFloat {
        return (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}

With iPhone-X, height of top bar (navigation bar + status bar) is changed (increased).

Try this if you want exact height of top bar (both navigation bar + status bar):

UPDATE

iOS 13

As the statusBarFrame was deprecated in iOS13 you can use this:

extension UIViewController {

    /**
     *  Height of status bar + navigation bar (if navigation bar exist)
     */

    var topbarHeight: CGFloat {
        return (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}

Objective-C

CGFloat topbarHeight = ([UIApplication sharedApplication].statusBarFrame.size.height +
       (self.navigationController.navigationBar.frame.size.height ?: 0.0));

Swift 4

let topBarHeight = UIApplication.shared.statusBarFrame.size.height +
        (self.navigationController?.navigationBar.frame.height ?? 0.0)

For ease, try this UIViewController extension

extension UIViewController {

    /**
     *  Height of status bar + navigation bar (if navigation bar exist)
     */

    var topbarHeight: CGFloat {
        return UIApplication.shared.statusBarFrame.size.height +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}

Swift 3

let topBarHeight = UIApplication.sharedApplication().statusBarFrame.size.height +
(self.navigationController?.navigationBar.frame.height ?? 0.0)


Swift version:

let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height

iOS 14

For me, view.window is null on iOS 14.

extension UIViewController {
    var topBarHeight: CGFloat {
        var top = self.navigationController?.navigationBar.frame.height ?? 0.0
        if #available(iOS 13.0, *) {
            top += UIApplication.shared.windows.first?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
        } else {
            top += UIApplication.shared.statusBarFrame.height
        }
        return top
    }
}

Swift 5

If you want to get the navigation bar height, use the maxY property that considers the safeArea size as well, like this:

 let height = navigationController?.navigationBar.frame.maxY