让 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.clipsToBounds
是 false
。但是在你推动另一个控制器并弹回之后,_UINavigationBarContentView.clipsToBounds
是 true
。这就是 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起作用
点击 NavigationBar 和 NavigationBar 项时 UIPopoverController 不会关闭