iOS 11 UINavigationBar UISearchBar 和 UIBarButtonItem 重叠

iOS 11 UINavigationBar UISearchBar and UIBarButtonItem overlap

在iOS11中,如果你设置一个UISearchBar为navigationItem的titleView。然后添加/删除 UIBarButtonItem 到 navigationItem.leftBarButtonItems。 UIBarButtonItem 将与 UISearchBar 重叠。

重现步骤:

  1. 新建单一视图Xcode 项目
  2. 在故事板的 UINavigationController 中嵌入 ViewController
  3. 像这样修改ViewController.swift

    class ViewController: UIViewController {
        let button = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil)
        override func viewDidLoad() {
            super.viewDidLoad()
            let searchBar = UISearchBar()
            searchBar.searchBarStyle = .minimal
            navigationItem.titleView = searchBar
        }
    
        override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
            super.traitCollectionDidChange(previousTraitCollection)
            if traitCollection.horizontalSizeClass == .regular {
                navigationItem.leftBarButtonItem = button
            } else {
                navigationItem.leftBarButtonItem = nil
            }
        }
    }
    

环境:Xcode9.2,iOS11.2.2

我的问题是:有没有办法让 UINavigationBar 正确布局项目,或者我在这里做错了什么?谢谢!

尝试DispatchQueue.main.async

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    DispatchQueue.main.async {
        if self.traitCollection.horizontalSizeClass == .regular {
            self.navigationItem.leftBarButtonItem = self.button
        } else {
            self.navigationItem.leftBarButtonItem = nil
        }
    }
}
override func viewDidLoad() {
    super.viewDidLoad()

    navigationController?.setNavigationBarHidden(true, animated: false)
    navigationController?.setNavigationBarHidden(false, animated: true)
}

重置 viewWillAppear 中的 navigationItem.titleView

设置 titleView = nil 并返回搜索栏以强制强制导航栏重新布局。

类似于:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    navigationItem.titleView = nil
    navigationItem.titleView = self.searchBar
}

更多详情

我喜欢使用 traitCollectionDidChange 的公认解决方案。

但是,该解决方案不适用于(并且仅适用于!)iPhone 11 Pro Max(目前iOS 14.4)。

这是一个非常奇怪的问题,但 viewWillAppear 中的重置是我发现适用于所有设备的唯一可靠解决方案。