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

时间:2011-09-05 19:30:42

标签: ios objective-c swift uinavigationcontroller uinavigationbar

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

那么如何确定此导航栏的高度,而不仅仅是将其设置为常量?

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


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

我相信我的整个问题都集中在我的autoresizingMasks上。并且我得出结论的原因是存在相同的症状,有或没有UIWebView。而这种症状是肖像的一切都是桃色的。对于Landscape,最底部的UIButton会弹出TabBar。

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

UIView - 弹簧设置(默认情况下)和没有支柱

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

UILabel和UIImage接下来垂直 - 顶部支撑设置,灵活到其他地方

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

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

UIButton - 没有任何设置,即在任何地方都是灵活的

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


请耐心等待我,因为我需要更多的空间,而不是简短的回复评论。

感谢您试图了解我真正想要捕获的东西......所以这里有。

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

所以,UIImage,文本等UIWebView(在SOME上)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的高度。

那么你有它。

15 个答案:

答案 0 :(得分:230)

做这样的事情?

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

swift版本为located here

答案 1 :(得分:56)

Swift 版本:

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

答案 2 :(得分:56)

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

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

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

答案 3 :(得分:6)

你试过这个吗?

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

答案 4 :(得分:6)

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

答案 5 :(得分:4)

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;

答案 6 :(得分:3)

雨燕5

如果您也想考虑safeArea:

 let height = navigationController?.navigationBar.frame.maxY  

答案 7 :(得分:2)

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

答案 8 :(得分:1)

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

我相信我的整个问题都集中在我的autoresizingMasks上。并且我得出结论的原因是存在相同的症状,有或没有UIWebView。而这种症状是肖像的一切都是桃色的。对于Landscape,最底部的UIButton会弹出TabBar。

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

UIView - 弹簧设置(默认情况下)和没有支柱

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

UILabel和UIImage 下一个垂直 - 顶部支柱设置,灵活到处都是

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

UIWebView - Struts:顶部,左侧,右侧 斯普林斯:两个

UIButton - 没有设置,即到处灵活

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

答案 9 :(得分:1)

以下是我对您的更新的回复的开始:

  

为什么我的UIWebView的内容高度不会因轮换而改变?。

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

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

您可能已经查看了该选项,但只是将其丢弃。

另一个想法是,您是否可能检测到您正在旋转的方向,只需以编程方式放置按钮以调整标签栏。 (这可以通过代码实现)

答案 10 :(得分:1)

我的应用程序有几个视图,需要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 :(得分:0)

我用过:

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

如果要获取导航栏的高度及其Y原点,效果很好。

答案 12 :(得分:0)

便捷的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()

答案 13 :(得分:0)

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

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

但是,如果您需要iPhone的顶部高度,则不需要获取navigationBar高度并将其添加到statusBar高度,您只需调用safeAreaInsets这就是为什么存在。

self.view.safeAreaInsets.top

答案 14 :(得分:0)

Swift:以编程方式在导航栏正下方添加网络视图

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