31
votes

I have a UITableViewController with a UISearchBar and UISearchDisplayController. That exists inside a Container View in a UIViewController which is in a UINavigationController. I made this image to help describe the structure:

enter image description here

This is what it really looks like:

enter image description here

When I tap the Search Bar, I have to hide the Nav Bar. Normally, this would happen on its own, but since my UITableViewController is inside a Container View, I have to handle that change myself. This is what it looks like then, note that the Status Bar is white because the Nav Bar is white, even though it is Hidden at the moment.

enter image description here

Once I start typing in some search text, the results show up. If I scroll those results upward, they pass underneath the Search Bar, but they overlap the Status bar which is very unattractive.

enter image description here

If the Container View isn't involved, then this all works as intended and the table content passes underneath the Status Bar, but with the ContainerView involved, the table text and status bar collide.

How do I get the text to travel under the Status Bar like normal?

8

8 Answers

37
votes

I have search this for hours and my final result was to put this line in viewDidLoad: self.extendedLayoutIncludesOpaqueBars = YES;

Problem solved :)

5
votes

Try setting the definesPresentationContext in viewDidLoad of your TableViewController

Swift

override func viewDidLoad() {
    super.viewDidLoad()

    definesPresentationContext = true
}

Objective-C

- (void)viewDidLoad {
    [super viewDidLoad];

    self.definesPresentationContext = YES;
}
4
votes

Here's what worked for me:

DO:

  • Use UISearchController (not a separately placed UISearchBar)
  • Place your VC in a UINavigationController if it isn't already. Set the nav not to "Show Navigation Bar" if desired.
  • Use autolayout for the UITableView (not springs and struts) and pin the top of the table to the top of the VC's view.
  • Add this delegate method:

- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar { return UIBarPositionTopAttached; }

DON'T:

  • Fiddle with edgesForExtendedLayout
  • Fiddle with extendedLayoutIncludesOpaqueBars
  • Fiddle with the table's contentInset
3
votes

I have UISearchBar and UISearchDisplayController.

In viewdidload:

self.edgesForExtendedLayout = UIRectEdgeNone;
[searchDisplayController.searchBar setBackgroundImage:[self imageWithColor:ETSBaseColor] forBarPosition:0 barMetrics:UIBarMetricsDefault];

method that obtain image from UIColor:

- (UIImage *)imageWithColor:(UIColor *)color
{
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}
2
votes

Basically this is due to the traslucency of the nav bar, usually the view controller fix that overlapping, by correcting the top insets of the owned view or subview if they are(or inherits) from UIScrollView. You have 2 options, one is to set the traslucency of the navbar to no, the other is set the edgeForExtendedLayout to none ore leave only bottom.

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
    self.navigationController.navigationBar.translucent = YES;
}

- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
    self.navigationController.navigationBar.translucent = NO;
}

These advices works only on iOS7, if you are deploying on lower target check before settings those properties.
Another way around, but I didn't tested could be read the --topLayoutGuide length and in the -searchDisplayControllerWillBeginSearch try to set a topInsets of the same length. In this way you should still preserve the translucency.

0
votes

I had the same problem:

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    controller.searchBar.searchBarStyle = UISearchBarStyleDefault; // Used to cover UIStatusBar
}

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
    controller.searchBar.searchBarStyle = UISearchBarStyleMinimal; // Used not to show top and bottom separator lines
}
0
votes

In my case I don't want to hide the UINavigationBar but I had similar problems with gapes and other side effects. One of them was a missing UISearchBar after switching between UIViewControllers while the UISearchDisplayController is visible (I'm using SWRevealViewController to switch between UIViewController). This problem occurs only on iPads. It came out that the UISearchBar suddenly hides behind the UINavigationBar. Now I solved all my Problems with the following lines of code in the UITableViewController which is presented in a UIContainerView:

- (UINavigationController *)navigationController {
    return nil;
}

Those lines prevent the UISearchDisplayController to reach and change my UINavigationController. I also subclassed this method into "MyContainerTableViewController" class and use this class now for all embedded UITableViewController.

I'm still using UISearchDisplayController to Support iOS 7.

0
votes

The following hack worked for me:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return (self.searchController.isActive  && section == 0) ? 22.0f : 0.0f;
}