以编程方式获取导航栏的高度
Posted
技术标签:
【中文标题】以编程方式获取导航栏的高度【英文标题】:Programmatically get height of navigation bar 【发布时间】:2011-11-10 20:11:49 【问题描述】:我知道更多视图控制器(导航栏)的存在将 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 (on SOME) UIButton
围绕着以上所有的是一个 UIScrollView。
2) 对于那些有 UIWebView 的,它的 autoresizingMask 看起来像:
—
|
—
^
|
|
|—| ←----→ |—| | | 五 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 的高度。
你有它。
【问题讨论】:
【参考方案1】:Swift : 以编程方式在导航栏下方添加一个 Web 视图
从ios11开始,定位导航栏下方视图的关键是使用safeAreaLayoutGuide
来自 Apple 文档 (link):
表示视图中未被条形和其他内容遮挡的部分的布局指南。
所以在代码中我将使用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)
])
【讨论】:
【参考方案2】:斯威夫特 5
如果要获取导航栏高度,请使用maxY
属性,该属性也考虑了安全区域的大小,如下所示:
let height = navigationController?.navigationBar.frame.maxY
【讨论】:
应该是答案。你拯救了我的一天。【参考方案3】: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
【讨论】:
【参考方案4】:方便的 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()
【讨论】:
在没有 VC 的情况下作为静态成员的不错的解决方案【参考方案5】:支持 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
【讨论】:
对我来说,view.window 是零。所以我必须从UIApplication.shared.windows
的keywnidow 中取帧。 (iOS 14)【参考方案6】:
如果你只想得到navigationBar
的高度,很简单:
extension UIViewController
var navigationBarHeight: CGFloat
return self.navigationController?.navigationBar.frame.height ?? 0.0
但是,如果您需要 iPhone 的***高度,则无需获取navigationBar
高度并将其添加到statusBar
高度,您只需调用safeAreaInsets
这就是存在的原因。
self.view.safeAreaInsets.top
【讨论】:
【参考方案7】:在 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)
【讨论】:
Swift 4 答案为我返回 0 高度。【参考方案8】:做这样的事吗?
NSLog(@"Navframe Height=%f",
self.navigationController.navigationBar.frame.size.height);
swift版是located here
更新
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)
【讨论】:
谢谢,谢谢。但是,既然您已经解决了这个问题,那么我该如何确定 NavigationController(又名 MoreViewController)是否正在为我的标签栏应用程序显示。 我不太明白你想说什么。您是否想弄清楚 MoreViewController 是否正在显示? (如果是,你想做什么?)如果不是,你能澄清一下你的意思吗? 我又看了你的问题,还是没明白你想做什么?如果你想在视图出现时做一些事情,你应该将代码插入到 viewDidAppear 中。如果你澄清一点,它会更容易弄清楚你想做什么。 我知道这并没有解决他提出的问题,但似乎他正在查看 navigationBar 是否隐藏。如果是这样,他本可以使用 self.navigationController.navigationBarHidden 希望这对某人有帮助:) 在 iOS 7+ 中,您可能还需要根据您的应用程序考虑 20px 状态栏【参考方案9】:我用过:
let originY: CGFloat = self.navigationController!.navigationBar.frame.maxY
如果您想获取导航栏高度及其 Y 原点,那就太好了。
【讨论】:
我认为这是最好的方法,因为 maxY 值是导航栏和状态栏的高度。【参考方案10】:我的应用程序有几个视图,需要在 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];
最后,一个完美的导航栏看起来和内置的一模一样!
【讨论】:
【参考方案11】:你试过了吗?
let barHeight = self.navigationController?.navigationBar.frame.height ?? 0
【讨论】:
【参考方案12】: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;
【讨论】:
【参考方案13】:Swift 版本:
let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
【讨论】:
总是返回44。如何知道折叠尺寸(44)或展开尺寸(大标题)???当然是动态的。 (我知道它测量的是什么)【参考方案14】:这是我对您的更新的回应的开始:
为什么我的 UIWebView 的内容高度不随旋转而变化?
可能是因为您的自动调整大小没有针对所有方向的 autoresizingMask 吗?
在我回来之前的另一个建议是,您能否根据需要使用工具栏。它有点简单,总是在底部,自动旋转/定位。您可以随意隐藏/显示它等。有点像这样:http://cdn.artoftheiphone.com/wp-content/uploads/2009/01/yellow-pages-iphone-app-2.jpg
您可能已经看过该选项,但只是将其扔掉。
另一个想法,您是否可以检测到您旋转的方向,然后以编程方式放置按钮以调整标签栏。 (这可以通过代码实现)
【讨论】:
在解决这个问题大约 2 周后,我决定通过在 UIWebView 子视图下方放置一个 UIButton 来使“问题”变得更加困难。所以,我把按钮放在它上面。坦率地说,它看起来并不“正确”……但它现在可以正常工作了。 UIWebView 的下方或上方设置了顶部支柱和水平弹簧。顺便说一句,它的 UIWebView 的 contentHeight 不会随旋转而改变。【参考方案15】:灯泡开始亮了。不幸的是,我还没有找到一种统一的方法来纠正这个问题,如下所述。
我相信我的整个问题都集中在我的 autoresizingMasks 上。我得出结论的原因是存在相同的症状,无论有没有 UIWebView。那个症状是肖像的一切都是桃色的。对于横向,最底部的 UIButton 在 TabBar 后面弹出。
例如,在一个 UIView 上,我有,从上到下:
UIView – 两个弹簧设置(默认情况)和没有支柱
UIScrollView - 如果我设置了两个弹簧,并清除了其他所有内容(如 UIView),那么 UIButton 会侵入它正上方的对象。 如果我清除所有内容,那么 UIButton 就可以了,但最上面的东西隐藏在 StatusBar 后面 仅设置顶部支柱,UIButton 会在 Tab Bar 后面弹出。
UILabel 和 UIImage 下一个垂直 - 顶部支柱设置,其他任何地方都灵活
只是为了完成少数拥有 UIWebView 的图片:
UIWebView - 支柱:上、左、右 弹簧:两者
UIButton – 没有设置,即随处灵活
虽然我的灯泡很暗,但似乎还有希望。
【讨论】:
设置顶部支柱并设置 UIWebView 的两个弹簧 - 问题解决了,谢谢大家。事实上,我剩下的唯一问题就是设计那些被诅咒的@2X等图形。我以一种非常简单的方式使用 GraphicConverter,它非常适合网页设计,非常好。但是所有这些 30 像素、57 像素的东西 - 至少我要进入未知领域。以上是关于以编程方式获取导航栏的高度的主要内容,如果未能解决你的问题,请参考以下文章