I want to place an image in the middle of a navigation bar that is bigger then the bar itself. So far I tried to use a UIView with a UIImageView inside and it works quite we
I found why you got this issue. It's because of a private view which has name _UINavigationBarContentView
. It's a subview of UINavigationBar
. navigationItem.titleView
is contained in this view.
At first time, when you change navigationItem.titleView
. _UINavigationBarContentView.clipsToBounds
is false
.But after you push another controller and pop back, _UINavigationBarContentView.clipsToBounds
is true
. That's why titleView
is cropped.
So i have a temporary solution. Each time when viewController
appears, find this view and change _UINavigationBarContentView.clipsToBounds
to false
and layout 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()
}
I tried and it works. But i think you shouldn't do something whit it because it's private view. Maybe Apple don't want us do anything with it.
Hope somehow my suggestion can help you. Good luck ;)
SOLUTION
Adding observer for _UINavigationBarContentView.clipsToBounds
, each time when it changes to false
, set to true
and update layout of 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")
}
For more detail and easier, you can check my demo here https://github.com/trungducc/stackoverflow/tree/big-title-navigation-bar