【问题标题】:Is there a way to change the height of a UINavigationBar in Storyboard without using a UINavigationController?有没有办法在不使用 UINavigationController 的情况下更改 Storyboard 中 UINavigationBar 的高度?
【发布时间】:2013-12-24 16:56:00
【问题描述】:

我想在我的一个视图中使用自定义UINavigationBar,它不属于任何UINavigationController-hierarchy。当我将 UINavigationBar 拖到 Storyboard 中时,它显示如下:

这个栏是 44px,如果状态栏不共享这个空间就足够了。因为 iOS7 允许我们使用整个屏幕,包括状态栏的空间,UINavigationBar 应该是 64px 高,而不是 44px。

如果我将视图连接到 UINavigationController 的层次结构,那么它显示正确:

我在某处读到如果UINavigationBar 的属性barPosition: 设置为UIBarPositionTopAttached,那么条形将为64 像素。然而,这是一个readonly-property。

我的搜索结果只显示了我认为“解决方法”的内容。通过在UIViewController之前添加一个无用的UINavigationController,我可以假装有一个层次结构,它会自动添加64px的UINavigationBar

真的没有办法拥有一个覆盖 64 像素的“流氓”(没有导航控制器的帮助)UINavigationBar? 如果是这样,是否有任何正当理由说明原因?

(我并不是说UINavigationBar 默认应该是 64px,但在检查器中应该有一个选项)

(我也看到人们用编程方式来解决这个问题。即使这些答案有效,我仍然必须设计考虑到这一点(差距)的故事板。我想要什么要知道是否可以在情节提要中设置它,或者更确切地说,为什么不允许这样做?)

【问题讨论】:

  • 使用 UINavigationController 时如何更改高度?我有一个 UINavigatioController 但该栏出现 44px

标签: ios objective-c cocoa-touch uinavigationcontroller uinavigationbar


【解决方案1】:

您可以通过编程方式更改导航栏高度:

[navBar setFrame:CGRectMake(0, 0, 320, 64)];

编辑:正如我在 cmets 中所写,您可能必须将此行放入 viewDidLayoutSubviews 以规避自动布局。

【讨论】:

  • 确实可以,我实际上从未尝试过,谢谢。但是,Storyboard 中的 height 属性是灰色的,所以我认为我们不能有 64px UINavigationBarin Storyboard 是有原因的,我想知道是什么原因是.. 如果我以编程方式更改高度,我仍然必须使用“错误”信息在 Storyboard 中设计控制器,无论是在导航栏下方有 20px 的间隙,还是在底部有 20px 的间隙时有约束视图等。我的问题是在情节提要中的有限功能。
  • 我在 viewDidLoad 和 didFinishLauchingWithOptions 中都试过了。导航栏的高度确实发生了变化,但再次设置为默认值。我是不是把你的想法弄错了,还是我可能会错过其他一些东西?
  • @jchnxu 尝试将其放入viewDidLayoutSubviews
  • 我发现这适用于viewDidAppear: 方法。但是......它下面的视图没有更新以匹配更改的高度。对答案的一个很好的增强将显示您如何调整其他视图(它会是显示在层次结构中的UINavigationTransitionView 吗?)以与大小的变化同步(在我的情况下,我试图使其更窄,而不是更大)。
  • 这适用于 swift:override func viewDidLayoutSubviews() { let theWidth = view.frame.size.width navBar.frame = CGRectMake(0, 0, theWidth, 64) }
【解决方案2】:

您可以通过其他方式将属性barPosition 设置为UIBarPositionTopAttached

  1. 为您的 UINavigationBar 添加一个代理。
  2. 在委托类中实现-positionForBar:

    - (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
    {
        return UIBarPositionTopAttached;
    }
    

您的导航栏顶部也必须锚定到顶部布局指南。

【讨论】:

  • 它正在工作,我认为这是最优雅的解决方案。问题是当 UINavigationBar 不在 UINavigationController 中时,如何在状态栏下方扩展它。
  • 尽管“这是迄今为止最好的选择”cmets 是陈词滥调,但这是迄今为止最好的选择。
  • 啊,是的,如果我使用约束将 navigationBar 锁定到 topLayoutGuide(向下 20px),那么这似乎工作得很好,谢谢!尽管如此,仍然希望支持通过 Storyboard 使其工作(视觉上),但我猜 Apple 不会让我们这样做..
  • 如何在 Swift 中实现这一点?您说为 UINavigationBar 设置委托,即 UINavigationBarDelegate,但您引用的方法是 UIBarPositioningDelegate 协议中的一种。
  • 我已经完成了一篇博文,介绍了如何设置它的步骤:Easily use a Navigation Bar without a corresponding Navigation Controller
【解决方案3】:

我也在使用独立的 UINavigationBar,遇到了同样的问题,我发现有两种方法可以正确解决这个问题。

我使用约束和父 UIView 修复了它。我在情节提要中将此 UIView 设置为具有 {0, 0, 320, 64} 框架的 UINavigationBar 的父视图。您可以添加一个或一组约束,强制 UINavigationBar 具有所需的大小。 鉴于您的父 UIView 在情节提要中有正确的框架,您可以照常在情节提要中布局其他视图。

现在,如果禁用自动布局,您可以按照 Lindsey 的回答中所述以编程方式更改条形高度。 -(void)viewDidLayoutSubviews 似乎是个不错的选择。

【讨论】:

  • 您的意思是添加另一个 UIView(主视图的子视图)以将 UINavigationBar 嵌入其中?而且,您能详细说明如何设置约束吗?
  • @leanne KKetch 的解决方案在 Xcode 7.2 中适用于我。您描述得对:只需将另一个 UIView 添加到主视图并将 UINavigationBar 添加为新 UIView 的子项。相对于 UIView 的 Superview 设置约束如下:Leading Space = 0,Trailing Space = 0,Top Space = 0,Height = 64。相对于 Superview(你的新 UIView)的 UINavigationBar 约束是:Trailing Space = 0 , 前导空格 = 0, 底部空格 = 0, 顶部空格 = 0
【解决方案4】:

您可以使用 Interface Builder 的“Identity Inspector”中的“User Defined Runtime Attributes”将其设置为附加到视图的顶部。设置barPosition 属性。

这是barPosition 属性的文档:https://developer.apple.com/library/ios/documentation/uikit/reference/UIBarPositioning_Protocol/Reference/Reference.html

【讨论】:

  • 我测试过这是 Swift 2.2/Xcode 7.3,它运行良好!不错!
【解决方案5】:

有一种方法可以在不使用UINavigationController 或以编程方式设置的情况下完成此操作。只需将导航栏上的高度限制设置为您想要的任何值,在本例中为 64。

您可以通过编程方式完成同样的事情:

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:navigationBar attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1 constant:64.0f]];

编辑:

正如@nerdist-colony 所指出的,在使用自动布局时,始终将translatesAutoresizingMaskIntoConstraints 设置为NO,否则可能会出现约束冲突。

【讨论】:

  • 我真的很喜欢这个主意。但是当我使用它时,我得到一个冲突解决错误:“<0x17008d430 v:><0x17828eba0 h="-&-" v="--&" v: :0x13f53ad30>
【解决方案6】:

@startupThekid:

如果您尝试更改由 UINavigationController 管理的 UINavigationBar 的自动调整大小掩码,iOS 将生成异常。

但是,您发布的目标 C 代码的 Swift 等效项是:

var navBar = self.navigationController!.navigationBar 

viewDidAppear()中:

navBar.setTranslatesAutoresizingMaskIntoConstraints = false

无论你需要在哪里设置约束:

var navBarHeightConstraint = 
      NSLayoutConstraint(item: navBar, attribute: .Height,
            relatedBy: .Equal, toItem: nil, 
            attribute: .Height, multiplier: 1, constant: height)

self.view.addConstraint(navBarHeightConstraint)

您应该能够根据需要修改约束的常量属性以更改导航栏高度,例如更改设备方向

【讨论】:

  • 你是对的!从我的角度来看,不加评论地投票是不行的。为此我 +1。
  • 应该是navBar.translatesAutoresizingMaskIntoConstraints = false
  • 啊,是的@MarkusRautopuro,我解决了这个问题。谢谢!
  • 你不需要 Swift 中的 ; :) (看来我也可以编辑这些 - 删除它)
  • 这仍然会导致应用程序抛出未捕获的异常:'Cannot choose layout method for UINavigationBar managed by a controller'。这就是我投反对票的理由。
【解决方案7】:

我在同一条船上遇到问题,但现在我已经解决了。我正在尝试做正确的事情以避免显式设置框架,这对于面向未来和轻松支持不同设备尺寸是可取的。就我而言,我想要导航栏下方的网络视图。

我将我的视图控制器设置为UINavigationBarDelegate 并实现positionForBar: 以返回UIBarPositionTopAttached,如user3269713's answer。似乎另一个技巧是使用自动布局将栏放置在 topLayoutGuide 下方。

我在以编程方式创建导航栏和 webview 后在 viewDidLoad 中使用的代码,我仍然看到栏停留在 44 高处,但无法立即看出原因:

    [navigationBar sizeToFit];
    navigationBar.delegate = self;
    [self.view addSubview:navigationBar];
    [self.view addSubview:webView];
    id guide = self.topLayoutGuide;
    NSDictionary *viewNamesDict = NSDictionaryOfVariableBindings(webView, navigationBar, guide);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[webView]|" options:0 metrics:nil views:viewNamesDict]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[guide][navigationBar][webView]|" options:0 metrics:nil views:viewNamesDict]];

但我对自动布局进行了更多思考和尝试,结果证明这就是我的问题的原因。我试图依靠导航栏的自动调整掩码中的翻译约束,但事实证明我需要明确定义它们。这是我的新viewDidLoad 代码:

    [navigationBar sizeToFit];
    navigationBar.delegate = self;
    navigationBar.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:navigationBar];
    [self.view addSubview:webView];
    id guide = self.topLayoutGuide;
    NSDictionary *viewNamesDict = NSDictionaryOfVariableBindings(webView, navigationBar, guide);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[navigationBar]|" options:0 metrics:nil views:viewNamesDict]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[webView]|" options:0 metrics:nil views:viewNamesDict]];
    NSString *verticalLayoutVisualExpression = [NSString stringWithFormat:@"V:|[guide][navigationBar(%f)][webView]|", navigationBar.frame.size.height];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalLayoutVisualExpression options:0 metrics:nil views:viewNamesDict]];

是的,正如我所希望的那样,当转向横向时,这会自动移动栏并且状态栏会隐藏。

(我衷心推荐一个像 Masonry 这样的自动布局助手,它使布局代码更简洁,而 Masonry 则负责为您关闭 translatesAutoresizingMaskIntoConstraints

【讨论】:

    【解决方案8】:

    我知道这是一种非常老套的方法,但对我来说它很有效。我有一个NavigationViewController,我想以模式加载一个 ViewController,它的顶部有一个UINavigationBar,带有完成和取消按钮。这是它的样子:

    如您所见,顶部有一条白色带,我希望它与UINavigationBar 的颜色相同。我没有以编程方式更改UINavigationBar 的高度,而是创建了一个新视图并将其背景颜色设置为等于UINavigationBar 的背景颜色(HEX = F8F8F8,RGBA = 248,248,248,1.0)。再一次,我知道这是超级hacky,但它为我完成了工作。这是现在的样子

    【讨论】:

    【解决方案9】:

    如果你使用 Autolayout,你可以将 UINavigationBar 的约束高度设置为 64 或更多。

    【讨论】:

      【解决方案10】:

      我写了一篇博文,详细介绍了如何以最少的代码干预来做到这一点。您的栏将在情节提要中显示一个间隙,但它会在设备上正常工作。简而言之,步骤是:

      1) 将导航栏添加到情节提要中的视图控制器。

      2) 为故事板中的导航栏设置约束:
      - Navigation Bar.Top = 顶部布局 Guide.Bottom
      - 导航栏.Leading = Superview.Leading
      - Navigation Bar.Trailing = Superview.Trailing

      3) 将故事板的导航栏作为@IBOutlet 连接到其视图控制器。

      4) 在视图控制器的类中,在类声明中添加一个 UINavigationBarDelegate 协议。

      5) 在视图控制器的 viewDidLoad 方法中,将导航栏的委托设置为 self。

      6) 在视图控制器中,添加 bar 定位委托的 positionForBar 方法。返回代表 TopAttached 的 UIBarPosition。 (注:UINavigationBarDelegate 继承自 UIBarPositioningDelegate 这个方法。)

      带有 GIF 图片的完整帖子在这里:
      Easily use a Navigation Bar without a corresponding Navigation Controller

      这些步骤适用于 Swift 2.1/Xcode 7.2

      【讨论】:

        【解决方案11】:

        在使用主情节提要的 Swift 3 中,您可以使用约束来更改高度并使其正常工作。这是我发现很容易实现的方式。

        Creating the constraints.

        What it looks like in the end.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-11-07
          • 2012-02-08
          • 2011-02-11
          • 2015-03-05
          • 1970-01-01
          • 1970-01-01
          • 2011-10-06
          相关资源
          最近更新 更多