Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this UISearchBar getting resized?

As shown below, my UISearchBar is getting resized when I tap on the search field. It animates nicely to cover the navigation bar, and then pop... it shrinks.

The setup

The UISearchBar is inside a vanilla UIView set as the tableHeaderView. I'm using a UIView (as opposed to setting the UISearchBar as the header) because I would like to put additional views in the header.

The view is defined in a XIB file and the UISearchBar is anchored to all of its borders. The constraints don't seem to matter; if I remove them, the same problem happens.

Experiments

Examining the view hierarchy in Reveal tells me that the UIView has the right size and the UISearchBar has width 1 (?!) when this happens.

As an experiment, I subclassed the UISearchBar and made intrinsicContentSize return {320,44}. With this the UISearchBar shows properly, but when I press Cancel I get the following exception:

 *** Assertion failure in -[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2903.23/UIView.m:8540
 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.'

The workaround

If I create everything by code, it just works.

_headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
searchBar.delegate = self;
[_headerView addSubview:searchBar];

_searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
_searchDisplayController.searchResultsDelegate = self;
_searchDisplayController.searchResultsDataSource = self;
_searchDisplayController.delegate = self;

_tableView.tableViewHeader = _headerView;

What is going on here? I clearly won't use nibs to work with UISearchBar anymore, but I would like to understand what the heck happened anyway.

like image 639
hpique Avatar asked Jan 29 '14 00:01

hpique


1 Answers

The difference is in the search bar's value of translatesAutoresizingMaskIntoConstraints. It defaults to NO for the XIB-based view and YES for the code-based view. Apparently, the search controller assumes a value of YES and doesn't set up any explicit constraints when it transplants the search bar.

Setting the value to YES in code should fix it (verified locally).

UPDATE

As noted in the comments, even with translatesAutoresizingMaskIntoConstraints = YES, the controller does not restore the header view to it's original state on cancel. But there does seem to be a workaround. You can create an outlet to your header view and restore it yourself in searchDisplayControllerDidEndSearch. I did a crude proof-of-concept (and updated my sample project):

- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
    self.tableView.tableHeaderView = self.headerView;
    [self.searchBar removeFromSuperview];
    self.searchBar.frame = CGRectMake(0, 20, 320, 44);
    [self.headerView addSubview:self.searchBar];
}
like image 157
Timothy Moose Avatar answered Nov 08 '22 18:11

Timothy Moose