从 iOS 8 开始 popoverController 就变成 UIPopoverPresentationController, 由于最近的项目中用到了UIPopoverPresentationController, 因此出于备忘的目的,在此记录下我踩过的坑。

  1. UIPopoverPresentationController 大小自适应
    UIPopoverPresentationController大小自适应可以通过修改UITableViewControllerpreferredContentSize属性来进行实现,首先在UITableViewController代码文件中,override 三个方法,如下:
override func viewWillAppear() {
    self.tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
}

override func observerValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
    self.preferredContentSize = tableView.contentSize
}

override func viewWillDisappear(_ animated: Bool) {
    tableView.removeObserver(self, forKeyPath: "contentSize")
}

这里需要注意只能 override viewWillAppear, viewWillDisappear两个方法,而不能 override viewDidAppear, viewDidDisappear两个方法,因为会抛出it is not registered as an observer错误,经过查阅 Apple Docs, 程序只会在view全部可见时才会添加 Observer, 因此,只有在viewWillAppear时添加 Observer 才会成功添加,这样在 removeObserver 的时候才不会出错。

  1. UIPopoverPresentationController 展示时 UINavigationBarItems 可以被点击
    当我们使用UIPopoverPresentationController时,会发现popover窗口在显示时,UINavigationBarItems 可以被点击,这就很不好了,因为这会使我们的 App 看上去很奇怪,因此需要将UIPopoverPresentationControllerpassthroughViews属性设定为nil,代码如下:
    // 相关属性的设定
    let popOver = viewController.popOverPresentationController
    viewController.isModalInPopover = false
    popOver?.permittedArrowDirections = .up
    popOver?.barButtonItem = self.navigationItem.rightBarButtonItem
    popOver?.delegate = self
    
    // 使用多线程将 passthroughViews 属性设定为 nil
    present(viewController, animated: true) { () -> Void in
        DispatchQueue.main.async { () -> Void in
            popOver?.passthroughViews = nil
        }
    }