以编程方式获取导航栏的高度

我知道更多视图控制器(导航条)的出现会使 UIView 的高度下降。我还知道这个高度 = 44px。我还发现,这种下推维持 [self.view].frame.origin.y = 0

那么,除了将导航条设置为常量之外,如何确定导航条的高度呢?

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


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

我相信我的整个问题集中在我的自动调整面具。我得出结论的原因是同样的症状存在,不管有没有 UIWebView。这个症状就是肖像画的一切都很美好。对于横向,最底部的 UIBButton 弹出在标签栏后面。

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

UIView-既设置了弹簧(默认情况下)又没有 Struts

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

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

只是为了完成少数拥有 UIWebView 的用户:

UIWebView-Struts: 顶部,左边,右边

UIButton-没有设置,也就是说,到处都是灵活的

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


请容忍我,因为我需要更多的空间比提供一个简短的回复意见。

谢谢你试着去理解我真正想要的是什么... 所以我要开始了。

1)每个 UIViewController (一个 TabBar 应用程序)上都有一个 UIImage,一些文本和其他东西。另一个公分母是底部的 UIButton。在一些 UIViewController 上,我在 UIButton 上面有一个 UIWebView。

所以,UIImage,text 等等

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

2)对于那些拥有 UIWebView 的用户,它的自动调整大小面具看起来像这样:

   —
|
—


^
|
|

| ー | ——→ | ー | | | V UIButton 的面具没有任何设置,也就是说,到处都有弹性

在 my-viewDidLoad 中,我调用 my-reposition Subviews,在其中执行以下操作:

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

如果我有一个 UIWebView,那么我确定它的 * content * 高度,并设置它的框架来包围整个内容。

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

一旦我这样做了,然后我通过编程将 UIButton 向下推,使它最终位于 UIWebView 的下方。

一切工作,直到我旋转它从肖像到景观。

我在 my-diRotateFromInterfaceDirecting 中调用 my-reposition SubView。

为什么我的 UIWebView 的内容高度不随着旋转而改变。

从肖像到风景,内容的宽度应该扩大,内容的高度应该缩小。它的视觉效果是应该的,但不是根据我的 NSLog。

无论如何,不管有没有 UIWebView,我说过的按钮在横向模式下都会移动到 TabBar 下方,但是它不会向上滚动让人看到。当我“使劲”滚动时,我看到它在 TabBar 后面,但随后它又“回落”在 TabBar 后面。

底线是,最后一点就是我询问 TabBar 和 NavigationBar 高度的原因,因为 TabBar 将自己置于 UIView 的底部,而 NavigationBar 将 UIView 向下推。

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

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

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

这就是了。

227101 次浏览

做这种事吗?

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

快速版本是 位于这里


更新

IOS13

由于 statusBarFrameiOS13中已被弃用,因此您可以使用以下命令:

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

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

我相信我的整个问题集中在我的自动调整面具。我得出结论的原因是同样的症状存在,不管有没有 UIWebView。这个症状就是肖像画的一切都很美好。对于横向,最底部的 UIBButton 弹出在标签栏后面。

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

UIView -既设置了弹簧(默认情况下) ,也没有 Struts

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

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

只是为了完成少数拥有 UIWebView 的用户:

UIWebView - Struts: top,left,right 两个都是

UIButton -无集合,即处处灵活

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

以下是我对你的更新的回应:

为什么我的 UIWebView 的内容高度不随着旋转而改变。

会不会是因为您的自动调整大小没有自动调整面具的所有方向?

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

你可能已经考虑过这个选择了,但是就这么直接说出来。

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

Swift 版本:

let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
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;

你试过这个吗?

let barHeight = self.navigationController?.navigationBar.frame.height ?? 0

使用 iPhone-X,顶部栏(导航栏 + 状态栏)的高度会改变(增加)。

如果你想要精确的顶部栏高度(导航栏 + 状态栏) ,试试这个:

更新

IOS13

由于 statusBarFrameiOS13中已被弃用,因此您可以使用以下命令:

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

目标 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)

为了方便起见,请尝试这个 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)
}
}

Swift 3

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

我的应用程序有几个视图,需要在 UI 中定制一个导航栏,用于外观和感觉,但是没有导航控制器。该应用程序需要支持 iOS 版本之前的 iOS 11,所以方便的安全区域布局指南不能使用,我必须调整的位置和高度的导航栏编程。

我直接将导航栏连接到它的视图上,跳过了上面提到的安全区域布局指南。而且状态栏高度可以很容易地从 UIApplication 检索到,但是默认的导航栏高度实际上是一个痛苦的屁股..。

我花了将近半个晚上的时间,进行了大量的搜索和测试,直到我最终从另一篇文章中得到了提示(虽然对我来说不起作用) ,你实际上可以从 UIView.sizeThatFits ()得到高度,像这样:

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


[super viewWillLayoutSubviews];
}

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

我用过:

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

如果你想得到导航条的高度和它的 Y 原点,这个工作很棒。

方便的斯威夫特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()

如果你只想得到 navigationBar的高度,这很简单:

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

然而,如果你需要的高度顶尖的 iPhone,你不需要得到的 navigationBar高度,并添加到它的 statusBar高度,你可以简单地调用 safeAreaInsets,这就是为什么存在。

self.view.safeAreaInsets.top

支持 iOS13及以下版本:

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

Swift 5

如果你想得到导航条的高度,使用 maxY属性,它也考虑了 safeArea 的大小,如下所示:

 let height = navigationController?.navigationBar.frame.maxY

IOS14

对我来说,view.window在 iOS14上是空的。

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: 通过编程方式在导航栏下面添加一个 web 视图

在 iOS11中,将视图定位在导航条下方的关键是使用 safeAreaLayoutGuide

摘自苹果文档(链接) :

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

因此,在代码中,我将使用 view.safeAreaLayoutGuide.topAnchor放置 top 约束

再举一个例子:

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