【问题标题】: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 的高度。

你有它。

【问题讨论】:

    标签: ios objective-c swift uinavigationcontroller uinavigationbar


    【解决方案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

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

          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

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

          【讨论】:

          • 谢谢,谢谢。但是,既然您已经解决了这个问题,那么我该如何确定 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 像素的东西 - 至少我要进入未知领域。
                猜你喜欢
                • 2013-12-14
                • 1970-01-01
                • 1970-01-01
                • 2015-06-26
                • 1970-01-01
                • 2022-01-16
                • 2011-07-20
                • 2012-10-11
                • 1970-01-01
                相关资源
                最近更新 更多