Make NavigationBar's titleView larger than itself

前端 未结 3 1245
挽巷
挽巷 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: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

提交回复
热议问题