Aaron Shekey
Aaron Shekey

Reputation: 941

UISearchBar to UISearchDisplayController transition is off by 20px

I'm implementing a UISearchBar on the top of a UITableView.

In my ViewDidLoad I've set self.edgesForExtendedLayout = UIRectEdgeNone.

Here's how I'm adding my UISearchBar. I'm just adding a UISearchBar to the header of my UITableView and adjusting the content offset:

// Table View
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.screenWidth, self.screenHeight)];

self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

// Customize table appearance
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
self.tableView.backgroundColor = [UIColor tableBackgroundColor];

// Define the table's datasource
self.tableView.dataSource = self;
self.tableView.delegate = self;

[self.view addSubview:self.tableView];


// Add a search bar to the header
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.screenWidth, 44)];
self.searchBar.tintColor = [UIColor primaryBrandedColor];
self.searchBar.placeholder = NSLocalizedString(@"Search", "Search placeholder");
self.searchBar.backgroundImage = [UIImage imageNamed:@"searchBarBackground"];
[self.searchBar setBackgroundImage:[UIImage imageNamed:@"searchBarBackground"] forBarPosition:UIBarPositionTopAttached barMetrics:UIBarMetricsDefault];
self.searchBar.barTintColor = [UIColor clearColor];
self.searchBar.delegate = self;

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setFont:[UIFont fontWithName:@"Whitney-Light" size:15]];

//Setup search display controller
self.searchController = [[HUMSearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.searchController.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;

// Add the searchBar and offset the table view so it's hidden by default.
self.tableView.tableHeaderView = self.searchBar;
self.tableView.contentOffset = CGPointMake(0.0, self.searchBar.frame.size.height);

It doesn't seem like anything is out of the ordinary here, but there's a 20px gap on the original tableview when the SearchDisplayController is displayed. In this example I've subclassed SearchDisplayController to not hide the NavigationBar to make it more clear what's happening.

Gap

A video capture of the transition: http://cl.ly/0y3L0Z1R1I0c/20pixels.mov

The things I've tried:

  1. Change the frame of my UITableView on searchDisplayControllerWillBeginSearch to move it up 20px. This breaks the transition. http://cl.ly/033q0L3G0p1T/origin.mov
  2. Change the scroll offsets on UITableView on searchDisplayControllerWillBegin. Similarly, this breaks the transition.
  3. Tried to manually animate the UISearchBar but I couldn't get that to work either.

Any ideas?

Upvotes: 6

Views: 3113

Answers (3)

rdnx
rdnx

Reputation: 1

Instead of assigning your UISearchBar directly as a tableHeaderView, create an empty UIView with the same size as the UISearchBar and add the UISearchBar as a subview to this view, which you assign as the tableHeaderView.

This will prevent the UITableView from getting pushed down when the UISearchBar begins editing.

Upvotes: 0

DesignatedNerd
DesignatedNerd

Reputation: 2534

\me waves at Aaron

This is what wound up working for us after a hell of a lot of banging my head against the wall. Note that we are keeping the Nav bar showing with the search bar.

Note: This is most likely going to break on iOS 8 since it goes view-diving based on some stuff I figured out using Reveal, so if anyone's got a less-fragile solution, I'd love to hear it.

- (UIView *)wrapperViewForTableView:(UITableView *)tableView
{
    //This was discovered via Reveal. May change for iOS 8.
    return tableView.subviews[1];
}

- (CGFloat)statusBarHeight
{
    return CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]);
}

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    //Don't animate - this bit works without animation. 
    UIView *wrapperView = [self wrapperViewForTableView:self.tableView];
    CGRect frame = wrapperView.frame;
    frame.origin.y -= [self statusBarHeight];
    frame.size.height += [self statusBarHeight];

    wrapperView.frame = frame;
}

- (void)searchDisplayControllerWillEndSearch:(HUMSearchDisplayController *)controller
{
    //Animate this so it goes with the dismissal.
    [UIView animateWithDuration:0.25 animations:^{
        UIView *wrapperView = [self wrapperViewForTableView:self.tableView];
        CGRect frame = wrapperView.frame;
        frame.origin.y += [self statusBarHeight];
        frame.size.height -= [self statusBarHeight];
        wrapperView.frame = frame;
    }];
}

Upvotes: 0

Ergun Coruh
Ergun Coruh

Reputation: 385

After several trial and error sessions finally I achieved the desired behaviour. Note in my case when the search bar is clicked I want the navigation bar pushed up. The following solution fixes the 20px gap problem.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    ...        
    self.edgesForExtendedLayout = UIRectEdgeTop;
    self.searchBar.clipsToBounds = YES;
    self.navigationController.navigationBar.translucent = YES;
}

On viewWillDisappear the translucent property needs to be set to NO, otherwise in the segue view controllers navigation bar remains pushed along with view content.

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self resignFirstResponder];
    self.navigationController.navigationBar.translucent = NO;
}

Hope this helps.

Upvotes: 3

Related Questions