让 NavigationBar 的 titleView 比自己大

Posted

技术标签:

【中文标题】让 NavigationBar 的 titleView 比自己大【英文标题】:Make NavigationBar's titleView larger than itself 【发布时间】:2017-11-05 12:13:58 【问题描述】:

我想在比导航栏本身大的导航栏中间放置一张图片。到目前为止,我尝试在内部使用带有 UIImageView 的 UIView,并且效果很好,您可以在此处看到:

但是,一旦我按下另一个控制器并弹回我的 ImageView 就会再次裁剪为 NavigationBar 的大小。

关于如何防止裁剪的任何想法?

到目前为止我的 ios 11 代码:

override func viewDidLoad() 
    super.viewDidLoad()

    let logo = UIImage(named: "Logo")
    let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
    let imageView = UIImageView(image: logo)
    imageView.frame = CGRect(x: 0, y: 0, width: titleView.frame.width, height: titleView.frame.height)
    titleView.addSubview(imageView)
    imageView.contentMode = .scaleAspectFit
    imageView.image = logo
    navigationItem.titleView = titleView

编辑:目前有一个临时解决方案,它使用观察者覆盖导致问题的视图的 clipsToBounds 属性:Link(向@ trungduc 为此)

【问题讨论】:

您的代码在我的模拟器上完美运行i.stack.imgur.com/KKCBT.png 感谢您的快速评论。我也在模拟器上试过。您是否按下了另一个控制器然后弹回来? 【参考方案1】:

我找到了您遇到此问题的原因。这是因为名称为_UINavigationBarContentView 的私有视图。这是UINavigationBar 的子视图。 navigationItem.titleView 包含在此视图中。

第一次,当你改变navigationItem.titleView_UINavigationBarContentView.clipsToBoundsfalse 。但是在你推动另一个控制器并弹回之后,_UINavigationBarContentView.clipsToBoundstrue。这就是 titleView 被裁剪的原因。

所以我有一个临时解决方案。每次出现viewController,找到这个视图,把_UINavigationBarContentView.clipsToBounds改成false,布局titleView

override func viewDidAppear(_ animated: Bool) 
    for view : UIView in (navigationController?.navigationBar.subviews)! 
      view.clipsToBounds = false;
    
    navigationItem.titleView?.layoutIfNeeded()
  

  override func viewWillAppear(_ animated: Bool) 
    for view : UIView in (navigationController?.navigationBar.subviews)! 
      view.clipsToBounds = false;
    
    navigationItem.titleView?.layoutIfNeeded()
  

我试过了,效果很好。但我认为你不应该这样做,因为它是私人观点。也许 Apple 不希望我们对它做任何事情。

希望我的建议能对你有所帮助。祝你好运;)

解决方案

_UINavigationBarContentView.clipsToBounds添加观察者,每次更改为false时,设置为true并更新titleView的布局

override func viewDidLoad() 
  super.viewDidLoad()
  // Do any additional setup after loading the view, typically from a nib.

  let logo = UIImage(named: "Logo")
  let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
  let imageView = UIImageView(image: logo)
  imageView.frame = CGRect(x: 0, y: 0, width: titleView.frame.width, height: titleView.frame.height)
  titleView.addSubview(imageView)
  imageView.contentMode = .scaleAspectFit
  imageView.image = logo
  navigationItem.titleView = titleView
  navigationController?.navigationBar.subviews[2].addObserver(self, forKeyPath: "clipsToBounds", options: [.old, .new], context: nil)


override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 
  if  (navigationController?.navigationBar.subviews[2].isEqual(object))! 
    DispatchQueue.main.async 
      self.navigationController?.navigationBar.subviews[2].clipsToBounds = false
      self.navigationItem.titleView?.layoutIfNeeded()
    
  


deinit 
  navigationController?.navigationBar.subviews[2].removeObserver(self, forKeyPath: "clipsToBounds")

更多细节和更简单,你可以在这里查看我的演示https://github.com/trungducc/***/tree/big-title-navigation-bar

【讨论】:

感谢您的调查,这可能会帮助我们找到解决方案:) @palme 如果你能修复它,请告诉我。我很想看看你是怎么解决的;) @palme 另一种方法是为_UINavigationBarContentView.clipsToBounds 添加观察者。每次更改为false 时,再次将其更改为true 并布局视图。我不擅长 Swift,所以我不能尝试,但我认为你应该尝试 ;) 我喜欢你的两个想法,谢谢分享。不幸的是,当我实施您的第一种方法时,我有一个闪烁(也许您没有看到它,因为您没有调用超级函数)。老实说,我无法让观察者工作。我知道原理,但 _UINavigationBarContentView 上的属性 clipsToBounds 的观察者的委托从未被调用过。 感谢您的努力!我可以批准,效果很好。正如您所说,这可能只是一个临时解决方案,但至少您找到了解决方案。再次感谢您的调查。【参考方案2】:

如果您想要自定义高度,但 UINavigationBar 具有 UIBarMetrics 但它不是完全交互的。

Apple 建议 a bunch of code 实际开发像 iMessage 应用程序这样的好东西。

【讨论】:

不错!我去看看。【参考方案3】:

您可以尝试将代码放在 viewWillAppear 方法中。这样,您将在每次视图出现时将图像添加到栏。但是,您应该在 viewDidDissappear 方法中删除 inageview。如果您在多个视图中需要它,您可以继承 UIViewController 并使用这个。

【讨论】:

正如@trungduc 提到的,一旦你回到视图控制器,就会有子视图_UINavigationBarContentView,它将启用clipsToBounds,因此无论如何都会切断titleView。

以上是关于让 NavigationBar 的 titleView 比自己大的主要内容,如果未能解决你的问题,请参考以下文章

求助,不用鼠标的话怎么样才能让button的navigation起作用

TabBar 和 NavigationBar 视图部分隐藏

navigationBar上的一些操作

点击 NavigationBar 和 NavigationBar 项时 UIPopoverController 不会关闭

NavigationBar隐藏

navigationItem和navigationBar相关性