3
votes

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!

4

4 Answers

0
votes

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

// Swift 5

// if you are using UISearch Controller then simply add line below to your viewDidLoad() and it will fix the issue.

override func viewDidLoad() {
     super.viewDidLoad()

     // fixes the search moving to next screen when its active
     self.definesPresentationContext = true
}
0
votes

I believe putting searchBar inside tableView is not mandatory. I had same issue some time back. All you need to do is setting proper auto layout constraint. Adjust leading and trailing of searchView as align to leading and trailing of the tableView. Also release the margin property from constraints. Hope this may help you.

0
votes

After a few tries, I've found the reason being that when the UISearchBar is activated, UISearchController removes it from your view and puts it on its own view with a table view for showing the results, since I use auto-layout for the search bar, by removing it, some of the constraints are screwed up. So my solution was to not use auto layout for the UISearchBar from UISearchController.