UISearchController - 不能很好地使用子视图控制器

UISearchController - not playing well with child view controllers

我有一个问题,我当前的配置是:

UITableViewController -> UINavigationController -> A ViewController 用于换出 2 个子视图控制器。

每个子视图控制器都有一个与之关联的 UISearchController。当 UISearchBar 激活时,它似乎永远不会有正确的位置。

extension MySearchViewController: UISearchControllerDelegate {

    func willPresentSearchController(searchController: UISearchController) {
        var adjustedOrigin = searchController.searchBar.frame.origin
        //FIXME: There's some odd behavior with embedded child VCs where the status bar adjustments are not taken into consideration
        adjustedOrigin.y += UIApplication.sharedApplication().statusBarFrame.height
        searchController.searchBar.frame.origin = adjustedOrigin
        definesPresentationContext = false
        navigationController?.definesPresentationContext = true
        navigationController?.extendedLayoutIncludesOpaqueBars = true
    }

    func didPresentSearchController(searchController: UISearchController) {
        definesPresentationContext = true

    }

    func didDismissSearchController(searchController: UISearchController) {
        var adjustedOrigin = searchController.searchBar.frame.origin
        //FIXME: There's some odd behavior with embedded child VCs where the status bar adjustments are not taken into consideration
        adjustedOrigin.y -= UIApplication.sharedApplication().statusBarFrame.height

        searchController.searchBar.frame.origin = adjustedOrigin
    }

}

您可以在上面看到原点已调整,因为我正在尝试手动更正 UISearchBar 的偏移量,这目前不是首选。我已经尝试检查(在许多区域)故事板下的显示并通过代码几乎在层次结构中的任何地方。我似乎找不到抵消的罪魁祸首。默认情况下,UISearchBar 将一直显示在状态栏下方,如下所示:

这没有我的手动调整,仍然有点偏差。

有人对此有解决方案吗?


编辑 1:

进一步证明父级 VC 中的某些东西弄乱了偏移量,UISearchBar 的实际 superView 在呈现时偏移了 -20。因此,以下内容更正了该问题:

import UIKit

class MySearchController: UISearchController {

    override func viewDidLoad() {
        super.viewDidLoad()
        edgesForExtendedLayout = .Top
        extendedLayoutIncludesOpaqueBars = true
        automaticallyAdjustsScrollViewInsets = true 

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        print(active)

        if active && searchBar.superview!.frame.origin != CGPoint.zero {
            searchBar.superview?.frame.origin = CGPoint.zero
        }
    }
}

以下是我发现的唯一可以可靠地调整搜索控制器错误调整的状态栏偏移量的方法。

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    //FIXME: Unfortunate hack required to adjust for offset of -20 pulled from ????? where ?????
    guard let searchBarContainerView = searchBar.superview where (active && searchBarContainerView.frame.origin != CGPoint.zero) else {
        return
    }
    searchBarContainerView.frame.origin = CGPoint.zero
}

请注意,物理原点偏移了 -20 作为状态栏的高度。更正是为了确保将原点强制设置为 0。

另请注意,这是 UISearchController 子类中的重写方法。

供将来参考:通常这种怪异的关键是谁定义了表示上下文。

来自文档: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621456-definespresentationcontext

当出现 context-based 呈现时,UIKit 从呈现视图控制器开始,然后 遍历视图控制器层次结构。如果它找到一个视图控制器,其 属性 的值为 true,它会要求该视图控制器呈现新的视图控制器。如果没有视图控制器定义表示上下文,UIKit 将请求 window 的根视图控制器来处理表示。

因此,基本上您必须确保层次结构中的正确视图控制器将其设置为 definesPresentationContext 为 YES。如果放置正确,则无需偏移或修改框架。在您的情况下,可能是您的 parent VC 需要定义表示上下文并确保没有 child VC 将其设置为 YES。