Search code examples
iosswiftlayoutuisearchbaruisearchcontroller

UISearchController - not playing well with child view controllers


I have an issue where my current configuration is:

UITableViewController -> UINavigationController -> A ViewController for swapping out 2 child view controllers.

Each child view controller has a UISearchController associated with them. When the UISearchBar activates, it never seems to have the correct position.

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
    }

}

You can see in the above that the origin is adjusted as I'm trying to manually correct the offsets of the UISearchBar, which is by far not preferred. I've attempted checking off (in numerous areas) the display under from the storyboard and via code almost everywhere within the hierarchy. I can't seem to find the offsetting culprit. By default, the UISearchBar will appear all the way under the status bar as such:

search screen

This is without my manual adjustments which are still a bit off.

Does anyone have a solution for this?


Edit 1:

Further proof that something in a parent VC is messing up the offset, the actually superView of the UISearchBar is offsetted by -20 when presenting. Hence the following corrects the issue:

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
        }
    }
}

Solution

  • The following was the only way I found that could reliably adjusted for the status bar offset the search controller was incorrectly adjusting for.

    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
    }
    

    Note that the physical origin was offset by -20 being the height of the status bar. The correction was to ensure the origin was set to 0 forcefully.

    Also note that this is an overridden method within the UISearchController subclass.