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


131

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

因此,除了将其设置为常数之外,如何确定此导航栏的高度?

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


灯泡开始点亮。不幸的是,如下所述,我还没有发现纠正问题的统一方法。

我相信我的整个问题都围绕着我的自动调整大小掩码。我得出的结论是,无论是否使用UIWebView,都存在相同的症状。症状是,对于Portrait来说,一切都是桃红色的。对于Landscape,最底部的UIButton在TabBar后面弹出。

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

UIView –既设置了弹簧(默认情况),也没有支柱

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

UILabel和UIImage垂直向下–顶部支撑杆设置,其他位置均可灵活使用

只是为了完成一些具有UIWebView的图片:

UIWebView-支撑杆:顶部,左侧,右侧弹簧:两者

UIButton –没有设置,即到处都灵活

尽管我的灯泡昏暗,但似乎仍然充满希望。


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

感谢您尝试了解我真正在钓鱼的目的...

1)每个UIViewController(一个TabBar应用)都有一个UIImage,一些文本以及其他内容。另一个共同点是底部的UIButton。在某些UIViewController上,我在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的高度。

好吧,你有它。

Answers:


258

做这样的事吗?

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

谢谢谢谢。但是,既然您已经解决了该问题,那么如何确定我的选项卡栏应用程序的NavigationController(又名MoreViewController)是否正在显示。

我不太明白你想说的话。您是否要找出MoreViewController是否正在显示?(如果是这样,您想做什么?),如果不是,您能否阐明您的确切意思?
总和

我再次阅读了您的问题,但我仍然不明白您想做什么?如果要在显示视图时执行某些操作,则应将代码插入到viewDidAppear中。如果您澄清一点,它将使您更轻松地确定您想做什么。
总和

2
我知道这不能解决他所问的问题,但似乎他正在寻找导航栏是否被隐藏。如果是这样,他本可以使用self.navigationController.navigationBarHidden Hope完全可以帮助某人:)
taylorcressy 2014年

2
在iOS 7+中,您可能还需要根据应用程序考虑20px状态栏
Slayter

94

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

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


3
Swift 4答案为我返回0高度。
Chewie The Chorkie

61

迅捷版:

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

始终返回44。如何知道折叠尺寸(44)或扩展尺寸(大标题)???当然是动态的。(我知道该怎么衡量)
马库斯

6

你有尝试过吗?

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

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

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;

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

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


2

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

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

但是,如果您需要iPhone顶尖的高度,则无需获取navigationBar高度并将其添加到statusBar高度,您可以简单地将safeAreaInsets其称为“ 存在”。

self.view.safeAreaInsets.top

1

灯泡开始点亮。不幸的是,如下所述,我还没有发现纠正问题的统一方法。

我相信我的整个问题都围绕着我的自动调整大小掩码。我得出的结论是,无论是否使用UIWebView,都存在相同的症状。症状是“肖像”的一切都是桃红色的。对于Landscape,最底部的UIButton在TabBar后面弹出。

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

UIView –既设置了弹簧(默认情况),也没有支柱

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

UILabel和UIImage垂直向下–顶部支撑杆设置,其他位置均可灵活使用

只是为了完成一些具有UIWebView的图片:

UIWebView-支撑杆:顶部,左侧,右侧弹簧:两者

UIButton –没有设置,即到处都灵活

尽管我的灯泡昏暗,但似乎仍然充满希望。


设置顶部支撑杆并设置UIWebView的两个弹簧-问题已解决,感谢大家。实际上,我唯一剩下的问题是设计那些被诅咒的@ 2X等图形。我以一种非常简单的方式使用GraphicConverter,它非常适合网页设计。但是所有这些30px,57px的内容-至少对于我来说,我要进入未知的领域。

1

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

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

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

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

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

另一个想法是,您是否可以检测到旋转的方向,然后以编程方式放置按钮以调整选项卡栏。(这可以通过代码实现)


解决这个问题大约2周后,我认为通过将UIButton放在UIWebView子视图的下方,使“问题”变得更加困难。因此,我将按钮置于其上方。坦率地说,它看起来并没有那么“正确”……但现在可以正常使用了。在UIWebView的下方或上方已设置顶部支柱,而仅设置了水平弹簧。顺便说一句,它的UIWebView的contentHeight不会随着旋转而改变。

0

我用过了:

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

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



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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.