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.
Following on from what both @TimothyMoose and @hpique have said about setting translatesAutoresizingMaskIntoConstraints = YES (yuck)
In my code I have found that if I do the following to show the searchDisplayController
and do the opposite when closing the searchDisplayController,
Then my view remains unchanged (everything goes back to what I'm expecting)
if i do not call the following line when closing
Then the view screws up.
The reason for this I believe is that the NSAutoresizingMaskLayoutConstraint are asserting them self and as they are the last in the constraint list, the Layout engine brakes the real constraint to satisfy the unwanted NSAutoresizingMaskLayoutConstraint constraints.
The difference is in the search bar's value of
translatesAutoresizingMaskIntoConstraints
. It defaults toNO
for the XIB-based view andYES
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 insearchDisplayControllerDidEndSearch
. I did a crude proof-of-concept (and updated my sample project):