Search code examples
iosobjective-cuitableviewuisearchbaruisearchcontroller

UISearchBar of UISearchController moves off screen when active


I need to have a UISearchBar above a UITableView (ie. the search bar is not part of the table view), and what I found is that when the search bar is activated, it moves off screen.

I did a fair bit of search and could not find a solution, there are ‘search bar off screen’ issues but they are adding search bar to table's header view and tweaking properties like definesPresentationContext fixed it.

My view hierarchy:

VC’s view |— top view |— segmented control |— search bar |— table view

Looks like UISearchController expects the search bar to be inside the table view, and always shifts the table view so that the search bar moves to the very top of screen.

Anyone having the same issue and found a solution?

Thanks a lot!


Solution

  • Updates

    After further testing I decided to just implement the UISearchBar delegate and stop using the UISearchController since I was just reusing my UICollectionView for the results. Found a great guide on how three different methods to implement the SearchBar.

    Edge Case #1

    TLDR

    Enable clips to bounds on the containing view. Or if you have a collection view cell that has a user-generated content view, enable clips to bounds on that content view.

    Details:

    An additional very important fact is that you may have the search bar embedded in a container view. This can cause issues if the container view does not have clips to bounds enabled. Other examples of this being a problem is the user-generated content views in UICollectionViewCells. Compare the setting on a UITableViewCell auto-generated content view to observe the difference.

    Summary

    A Boolean value that determines whether subviews are confined to the bounds of the view. Declaration

    var clipsToBounds: Bool { get set } Discussion

    Setting this value to true causes subviews to be clipped to the bounds of the receiver. If set to false, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is false.

    Swift 4.x Solution

    In my case, this was happening both inside a UICollectionView and inside of a UIStackView. I was able to keep my searchBar in place after noticing the following info in the searchBar quick help.

    Summary

    The search bar to install in your interface. Declaration

    var searchBar: UISearchBar { get } Discussion

    Before presenting your searchable content, install the search bar in this property somewhere into your view controller’s interface. The search bar becomes the starting point for searching your contents. Interactions with the search bar are handled automatically by the UISearchController object, which notifies the object in the searchResultsUpdater property whenever the search information changes. To use a custom subclass of UISearchBar, subclass UISearchController and implement this property to return your custom search bar.

    After that I was able to resolve the issue successfully by doing the following:

    let searchController = UISearchController(searchResultsController: nil)
    var searchBar:UISearchBar!
    

    Sometime later I assign the searchBar from the searchController to the searchBar in my UIViewController...

    BTW - I embed my searchBar in a container UIView that has all the contraints I need to keep it in place.

    func setupSearchController<T:UIViewController>(delegate vc:T) where T: UISearchResultsUpdating, T:UISearchBarDelegate {
        searchBar = searchController.searchBar //this is the key
        searchController.searchResultsUpdater = vc
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = "Search".localized()
        searchController.dimsBackgroundDuringPresentation = false
        searchController.searchBar.delegate = vc
        searchController.searchBar.showsCancelButton = true
        definesPresentationContext = true
        self.searchMenu.addSubview(searchBar) 
        //searchMenu is a constrained UIView in my hierarchy
    }