148

我知道更多视图控制器(导航栏)的存在将 UIView 的高度向下推。我也知道这个高度 = 44px。我还发现这种下推可以保持[self.view].frame.origin.y = 0.

那么我如何确定这个导航栏的高度,而不是仅仅将它设置为一个常数呢?

或者,更短的版本,我如何确定我的 UIView 显示在顶部的导航栏?


灯泡开始亮了。不幸的是,我还没有找到一个统一的方法来纠正这个问题,如下所述。

我相信我的整个问题都集中在我的 autoresizingMasks 上。我得出结论的原因是存在相同的症状,无论有没有 UIWebView。那个症状是肖像的一切都是桃色的。对于横向,最底部的 UIButton 在 TabBar 后面弹出。

例如,在一个 UIView 上,我从上到下:

UIView - 两个弹簧组(默认情况)和没有支柱

UIScrollView - 如果我设置了两个弹簧,并清除了其他所有内容(如 UIView),那么 UIButton 会侵入其正上方的对象。如果我清除所有内容,那么 UIButton 就可以了,但最顶部的东西隐藏在 StatusBar 后面 仅设置顶部支柱,UIButton 会在 Tab Bar 后面弹出。

UILabel 和 UIImage 下一个垂直 - 顶部支柱集,其他任何地方都很灵活

只是为了完成少数拥有 UIWebView 的图片:

UIWebView - Struts:上、左、右 Springs:两者

UIButton – 没有设置,即随处灵活

虽然我的灯泡很暗,但似乎还有希望。


请多多包涵,因为我需要比提供简短回复评论更多的空间。

感谢您尝试了解我真正在钓鱼的目的……所以就这样吧。

1)每个 UIViewController(一个 TabBar 应用程序)都有一个 UIImage、一些文本和顶部的任何内容。另一个共同点是底部的 UIButton。在一些 UIViewControllers 上,我在 UIButton 上方有一个 UIWebView。

所以,UIImage,文本等 UIWebView(在某些地方) UIButton

围绕上述所有内容的是一个 UIScrollView。

2)对于那些有 UIWebView 的,它的 autoresizingMask 看起来像:

   —
   |
   —

   ^
   |
   |

|—| ←----→ |—| | | V UIButton的掩码没有任何设置,即随处灵活

在我的 -viewDidLoad 中,我调用我的 -repositionSubViews,在其中我执行以下操作:

如果没有 UIWebView,除了将放置在 IB 中的 UIButton 居中之外,我什么也不做。

如果我确实有一个 UIWebView,那么我确定它的 *content*Height 并设置它的框架以包含整个内容。

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

一旦我这样做了,然后我以编程方式将 UIButton 向下推,使其最终放置在 UIWebView 下方。

一切正常,直到我将它从纵向旋转到横向。

我在我的 -didRotateFromInterfaceOrientation 中调用我的 -repositionSubViews。

为什么我的 UIWebView 的内容高度不随旋转而变化?

从纵向到横向,内容宽度应该扩大,内容高度应该缩小。它在视觉上是应该的,但不是根据我的 NSLog。

无论如何,无论有没有 UIWebView,我谈到的按钮在横向模式下都会移动到 TabBar 下方,但它不会向上滚动以被看到。当我“大力”滚动时,我在 TabBar 后面看到它,但随后它“退回”到 TabBar 后面。

最重要的是,这最后是我询问 TabBar 和 NavigationBar 高度的原因,因为 TabBar 将自身放置在 UIView 的底部,而 NavigationBar 将 UIView 向下推。

现在,我将在这里添加一两条评论,因为它们之前没有意义。

在没有 UIWebView 的情况下,我保留了 IB 所看到的一切。

使用 UIWebView,我将 UIWebView 的 frame.height 增加到它的 contentHeight 并向上调整围绕所有子视图的周围 UIScrollView 的高度。

那么你有它。

4

15 回答 15

273

做这样的事情?

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

快速版本位于此处


更新

iOS 13

由于statusBarFrame不推荐使用,iOS13您可以使用它:

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)
    }
}
于 2011-09-05T19:38:23.217 回答
104

在 iPhone-X 中,顶部栏(导航栏 + 状态栏)的高度发生了变化(增加)。

如果您想要顶部栏的确切高度(导航栏+状态栏),请尝试此操作:

更新

iOS 13

由于statusBarFrame不推荐使用,iOS13您可以使用它:

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));

斯威夫特 4

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

为方便起见,试试这个 UIViewController 扩展

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)
    }
}

斯威夫特 3

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

于 2018-02-08T11:16:19.720 回答
63

斯威夫特版本:

let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
于 2014-12-14T16:13:13.693 回答
16

iOS 14

对我来说,view.window在 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
    }
}
于 2020-09-17T10:04:57.230 回答
11

斯威夫特 5

如果要获取导航栏高度,请使用maxY考虑安全区域大小的属性,如下所示:

 let height = navigationController?.navigationBar.frame.maxY  
于 2020-05-14T18:05:01.183 回答
9

支持iOS 13及以下:

extension UIViewController {

    var topbarHeight: CGFloat {
        if #available(iOS 13.0, *) {
            return (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
                (self.navigationController?.navigationBar.frame.height ?? 0.0)
        } else {
            let topBarHeight = UIApplication.shared.statusBarFrame.size.height +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
            return topBarHeight
        }
    }
}
于 2020-02-28T13:01:07.303 回答
7

你试过这个吗?

let barHeight = self.navigationController?.navigationBar.frame.height ?? 0
于 2017-01-30T05:57:45.407 回答
5
UIImage*image = [UIImage imageNamed:@"logo"];

float targetHeight = self.navigationController.navigationBar.frame.size.height;
float logoRatio = image.size.width / image.size.height;
float targetWidth = targetHeight * logoRatio;

UIImageView*logoView = [[UIImageView alloc] initWithImage:image];
// X or Y position can not be manipulated because autolayout handles positions.
//[logoView setFrame:CGRectMake((self.navigationController.navigationBar.frame.size.width - targetWidth) / 2 , (self.navigationController.navigationBar.frame.size.height - targetHeight) / 2 , targetWidth, targetHeight)];
[logoView setFrame:CGRectMake(0, 0, targetWidth, targetHeight)];
self.navigationItem.titleView = logoView;

// How much you pull out the strings and struts, with autolayout, your image will fill the width on navigation bar. So setting only height and content mode is enough/
[logoView setContentMode:UIViewContentModeScaleAspectFit];

/* Autolayout constraints also can not be manipulated since navigation bar has  immutable constraints
self.navigationItem.titleView.translatesAutoresizingMaskIntoConstraints = false;

NSDictionary*metricsArray = @{@"width":[NSNumber numberWithFloat:targetWidth],@"height":[NSNumber numberWithFloat:targetHeight],@"margin":[NSNumber numberWithFloat:20]};
NSDictionary*viewsArray = @{@"titleView":self.navigationItem.titleView};

[self.navigationItem.titleView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>margin=)-H:[titleView(width)]-(>margin=)-|" options:NSLayoutFormatAlignAllCenterX metrics:metricsArray views:viewsArray]];
[self.navigationItem.titleView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[titleView(height)]" options:0 metrics:metricsArray views:viewsArray]];

NSLog(@"%f", self.navigationItem.titleView.width );
*/

所以我们真正需要的是

UIImage*image = [UIImage imageNamed:@"logo"];
UIImageView*logoView = [[UIImageView alloc] initWithImage:image];
float targetHeight = self.navigationController.navigationBar.frame.size.height;
[logoView setFrame:CGRectMake(0, 0, 0, targetHeight)];
[logoView setContentMode:UIViewContentModeScaleAspectFit];

self.navigationItem.titleView = logoView;
于 2015-04-08T07:11:52.417 回答
3

方便的 Swift 4 扩展,以防对其他人有帮助。即使当前视图控制器不显示导航栏也可以工作。

import UIKit

extension UINavigationController {
  static public func navBarHeight() -> CGFloat {
    let nVc = UINavigationController(rootViewController: UIViewController(nibName: nil, bundle: nil))
    let navBarHeight = nVc.navigationBar.frame.size.height
    return navBarHeight
  }
}

用法:

UINavigationController.navBarHeight()
于 2019-08-01T17:10:07.480 回答
2

灯泡开始亮了。不幸的是,我还没有找到一个统一的方法来纠正这个问题,如下所述。

我相信我的整个问题都集中在我的 autoresizingMasks 上。我得出结论的原因是存在相同的症状,无论有没有 UIWebView。那个症状是肖像的一切都是桃色的。对于横向,最底部的 UIButton 在 TabBar 后面弹出。

例如,在一个 UIView 上,我从上到下:

UIView - 两个弹簧组(默认情况)和没有支柱

UIScrollView - 如果我设置了两个弹簧,并清除了其他所有内容(如 UIView),那么 UIButton 会侵入其正上方的对象。如果我清除所有内容,那么 UIButton 就可以了,但最顶部的东西隐藏在 StatusBar 后面 仅设置顶部支柱,UIButton 会在 Tab Bar 后面弹出。

UILabel 和 UIImage下一个垂直 - 顶部支柱集,其他任何地方都很灵活

只是为了完成少数拥有 UIWebView 的图片:

UIWebView - Struts:上、左、右 Springs:两者

UIButton – 没有设置,即随处灵活

虽然我的灯泡很暗,但似乎还有希望。

于 2011-09-07T13:14:41.057 回答
2

我的应用程序有几个视图,需要在 UI 中自定义导航栏以获得外观,但没有导航控制器。并且应用程序需要支持iOS 11之前的iOS版本,所以无法使用方便的安全区域布局指南,我必须通过编程调整导航栏的位置和高度。

我直接将导航栏附加到它的超级视图,跳过了上面提到的安全区域布局指南。并且状态栏高度可以很容易地从 UIApplication 中检索,但是默认的导航栏高度真的很痛苦......

它让我震惊了将近半个晚上,经过多次搜索和测试,直到我终于从另一篇文章中得到了提示(虽然对我不起作用),你实际上可以从 UIView.sizeThatFits() 中获得高度,就像这样:

- (void)viewWillLayoutSubviews {
    self.topBarHeightConstraint.constant = [UIApplication sharedApplication].statusBarFrame.size.height;
    self.navBarHeightConstraint.constant = [self.navigationBar sizeThatFits:CGSizeZero].height;

    [super viewWillLayoutSubviews];    
}

最后,一个完美的导航栏看起来和内置的一模一样!

于 2019-05-26T14:27:00.420 回答
2

如果您只想获得navigationBar高度,这很简单:

extension UIViewController{
   var navigationBarHeight: CGFloat {
       return self.navigationController?.navigationBar.frame.height ?? 0.0
   }
}

但是,如果您需要 iPhone 顶级的高度,您不需要获取navigationBar高度并添加statusBar高度,您可以简单地调用safeAreaInsets这就是存在的原因。

self.view.safeAreaInsets.top
于 2019-12-02T11:25:22.443 回答
1

这是我对您的更新的回应的开始:

为什么我的 UIWebView 的内容高度不随旋转而变化?

可能是因为您的自动调整大小没有针对所有方向的 autoresizingMask 吗?

在我回来之前的另一个建议是,您能否根据需要使用工具栏。它有点简单,总是在底部,自动旋转/定位。您可以随意隐藏/显示它等。有点像这样:http ://cdn.artoftheiphone.com/wp-content/uploads/2009/01/yellow-pages-iphone-app-2.jpg

您可能已经看过该选项,但只是将其扔在那里。

另一个想法,你能不能检测到你从哪个方向旋转,然后以编程方式放置按钮来调整标签栏。(这可以通过代码实现)

于 2011-09-09T05:23:24.660 回答
1

我用过:

let originY: CGFloat = self.navigationController!.navigationBar.frame.maxY

如果您想获得导航栏高度及其 Y 原点,则工作得很好。

于 2019-07-09T13:10:35.617 回答
-1

Swift:以编程方式在导航栏下方添加一个 Web 视图

从 iOS11 开始,将视图定位在导航栏下方的关键是使用safeAreaLayoutGuide

来自 Apple 文档(链接):

布局指南,代表视图中未被条形和其他内容遮挡的部分。

所以在代码中我将使用view.safeAreaLayoutGuide.topAnchor

同样,整个事情将是例如:

import WebKit

class SettingsViewController: UIViewController {
let webView = WKWebView()
let url = URL(string: "https://www.apple.com")

override func viewDidLoad() {
        super.viewDidLoad()
        configureWebView()
}

override func viewWillAppear(_ animated: Bool) {
        follow(url: url)
}

func follow(url: URL?) {
        if let url = url {
            let request = URLRequest(url: url)
            webView.load(request)
    }
}

func configureWebView() {
        view.addSubview(webView)
        webView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
}
}
于 2021-05-03T11:30:13.730 回答