Make NavigationBar's titleView larger than itself

前端 未结 3 1247
挽巷
挽巷 2021-01-14 13:51

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

相关标签:
3条回答
  • 2021-01-14 14:24

    You could try to put the code in the viewWillAppear method. This way you will add the image to the bar everytime the view appears. However you should then remove the inageview within the viewDidDissappear method. If you need it in several views you could subclass the UIViewController and use this one.

    0 讨论(0)
  • 2021-01-14 14:26

    The UINavigationBar has UIBarMetrics if you want a custom height but it's not fully interactive.

    There's a bunch of code suggested by apple to actually develop nice things like iMessage app.

    0 讨论(0)
  • 2021-01-14 14:32

    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

    0 讨论(0)
提交回复
热议问题