I'm trying to add searching to my UITableViewController
via UISearchDisplayController
, however I'm seeing a very weird animation glitch when searching begins and ends.
On iPhone, the animation into the navigation bar works fine. However, when ending search, the navigation bar lags behind the search bar while animating down. This causes a white strip to show between the navigation bar and the search bar. On iPad, the animations are completely messed up.
iPhone video
and
iPad video
As the above videos show, the stock apps do not suffer from these animation glitches. Does anybody have any ideas what is causing the issues?
I'm creating the UISearchDisplayController
with the following inside the "Master" view controller.
- (void)viewDidLoad
{
[super viewDidLoad];
UISearchBar* searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 44.0)];
searchBar.delegate = self;
self.tableView.tableHeaderView = searchBar;
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
}
I also tried doing this using Storyboards but the same animation glitches occur.
The white glitch you see is a tableview's background color which is visible through a gap between navbar and searchbar. The gap is definitely Apple developer's oversight.
So the solution looks like this:
- (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
UIView *topTableViewBG = [[UIView alloc] initWithFrame:CGRectMake(0, -64, CGRectGetWidth(self.tableView.bounds), 64)];
topTableViewBG.backgroundColor = self.navigationController.navigationBar.backgroundColor;
topTableViewBG.tag = 1234567;
[self.tableView insertSubview:topTableViewBG belowSubview:self.tableView.tableHeaderView];
}
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
[[self.tableView viewWithTag:1234567] removeFromSuperview];
}
here I add a custom view right under the search bar. It happens just before transition to normal VC. The view is positioned at the special point so it covers the gap between the navbar and the searchbar. After the transition is finished, I remove the custom view.
the solution above is good only if there is non-translucent navbar. For translucent navbar there is a challange to find correct color for our 'gap-stopper' view. But as soon we are pretty free to change searchbar color, we can use searchbar color for gap-stopper.
Lets make some changes to our code
First, we need non-translucent searchbar, so set background image to search bar:
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
[searchBar setBackgroundImage:[UIImage pixelImageWithColor:SEARCHBAR_GRAY_COLOR] forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
searchBar.delegate = self;
self.tableView.tableHeaderView = searchBar;
here is the UIImage category method, that was used above:
+ (UIImage *)pixelImageWithColor:(UIColor *)color {
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB ();
CGContextRef ctx = CGBitmapContextCreate (NULL, 1, 1, 8, 0, cs, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault);
CGColorSpaceRelease (cs);
CGContextSetFillColorWithColor (ctx, color.CGColor);
CGContextFillRect (ctx, CGRectMake (0.0f, 0.0f, 1.0f, 1.0f));
CGImageRef cgImage = CGBitmapContextCreateImage (ctx);
CGContextRelease (ctx);
UIImage *result = [UIImage imageWithCGImage:cgImage];
CGImageRelease (cgImage);
return result;
}
Then change our searchDisplayControllerWillEndSearch
method:
- (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
UIView *topTableViewBG = [[UIView alloc] initWithFrame:CGRectMake(0, -64, CGRectGetWidth(self.tableView.bounds), 64)];
topTableViewBG.backgroundColor = SEARCHBAR_GRAY_COLOR;
topTableViewBG.tag = 1234567;
[self.tableView insertSubview:topTableViewBG belowSubview:self.tableView.tableHeaderView];
}
and finally the searchDisplayControllerDidEndSearch
method remains unchanged:
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
[[self.tableView viewWithTag:1234567] removeFromSuperview];
}
Honestly this solution is more universal and it looks much prettier than one I've described in first part of the answer.
I find the best solution for me, it's looks exactly as I need, I'm using swift but if you need you can easily translate it to objective-c
self.edgesForExtendedLayout = .None
let barBacgroundView = UIView(frame: CGRectMake(0, 0, self.view.frame.size.width, 64))
barBacgroundView.backgroundColor = self.tableView.backgroundColor
UIApplication.sharedApplication().delegate!.window!!.insertSubview(barBacgroundView, atIndex: 0)
Insert this code in viewDidLoad()
and that's it. Hope this helps :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With