12

I have implemented the UISearchController and it is working great except...

When I click on the Search Bar the Navigation Bar disappears nicely as expected. When I rotate the phone to landscape view I get this view which makes sense.

enter image description here

However, when I rotate the phone back to portrait view (still selected in search type area) I get this following view.

enter image description here

You can see that the Navigation Bar never reappears. I feel I'm implementing a basic search controller. What could possibly be causing this?

self.venueSearchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.venueSearchController.searchResultsUpdater = self;
self.venueSearchController.searchBar.delegate = self;
self.venueSearchController.dimsBackgroundDuringPresentation = NO;
self.venueSearchController.hidesNavigationBarDuringPresentation = YES;
self.venueSearchController.searchBar.frame = CGRectMake(self.venueSearchController.searchBar.frame.origin.x, self.venueSearchController.searchBar.frame.origin.y, self.venueSearchController.searchBar.frame.size.width, 44.0);

self.definesPresentationContext = YES;

self.navigationController.navigationBar.translucent = YES;
self.venueSearchController.searchBar.translucent = YES;

self.tableView.tableHeaderView = self.venueSearchController.searchBar;
aherrick
  • 18,488
  • 29
  • 100
  • 168
  • This is default behaviour of UISearchController, Navigation Bar hides when search type area is active and Navigation Bar shows when click on Cancel, is this your behaviour? – Yuvrajsinh Feb 19 '15 at 12:14
  • No, my problem is that in the second screenshot the search bar is behind the time/battery/carrier header which is not correct – aherrick Feb 19 '15 at 14:09
  • Reson for your search bar is behind the time/battery/carrier header is you given height = 44 for your searchBar.frame, it think it should be 64, as status bar occupies 20px height from top. – Yuvrajsinh Feb 20 '15 at 06:54
  • No i do not believe this is correct. The UI Search Controller should automatically reset the navigation bar height after rotating the phone back to portrait mode – aherrick Feb 21 '15 at 21:26
  • @aherrick you've set the searchBar delegate but not implemented the necessary methods. See my answer below – Stephen Furlani Feb 24 '15 at 14:30

5 Answers5

15

It looks like the UISearchController forgets to reset the frame of the searchBar when the status bar reappears. I think this is probably a bug in UISearchController; there seem to be a few listed in radar. It seems the searchBar's superview (which is internal to the UISearchController) ends up with the wrong height. This is vexing since the solution therefore involves reaching into the searchController's view hierarchy, which Apple could change... you might want to add a check of the iOS version so it only runs for specified versions.

If you add the code below to your view controller, it will be called when the trait collection changes. It checks to see a) the search controller is active, b) the statusBar is not hidden, and c) the searchBar origin-y is 0, and if so it increases the height of the superview by the height of the statusBar, which moves the searchBar down.

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    let app = UIApplication.sharedApplication()
    if searchController!.active && !app.statusBarHidden && searchController?.searchBar.frame.origin.y == 0 {
        if let container = self.searchController?.searchBar.superview {
            container.frame = CGRectMake(container.frame.origin.x, container.frame.origin.y, container.frame.size.width, container.frame.size.height + app.statusBarFrame.height)
        }
    }
}

Objective C

- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {

    [super traitCollectionDidChange: previousTraitCollection];

    if(self.venueSearchController.active && ![UIApplication sharedApplication].statusBarHidden && self.venueSearchController.searchBar.frame.origin.y == 0)
    {
        UIView *container = self.venueSearchController.searchBar.superview;

        container.frame = CGRectMake(container.frame.origin.x, container.frame.origin.y, container.frame.size.width, container.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height);
    }
}
aherrick
  • 18,488
  • 29
  • 100
  • 168
pbasdf
  • 20,407
  • 3
  • 36
  • 65
  • thanks for your thoughts.. is this a Swift method only? trying to find the Objective C version of this and I'll give it a go! – aherrick Feb 26 '15 at 14:50
  • 1
    Sorry, for some reason I thought you were using Swift. But it is available in Obj-C. It's in a protocol which (amongst others) is adopted by UIViewController. The Apple Docs are [here](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITraitEnvironment_Ref/index.html). – pbasdf Feb 26 '15 at 14:55
  • Looks like this might be exactly what I needed! here is the ObjC version I am currently testing. Going to keep playing with it but if it's looking good +50 – aherrick Feb 26 '15 at 22:49
  • 1
    @aherrick I hope it does the job. I remembered the super call in bed last night, but forgot to add it to my answer. But you've sorted it. – pbasdf Feb 26 '15 at 22:55
  • when rotate 180 degree, then above code is not worked for me. So i used container fame change code in didRotatefunction also. – Sabareesh Dec 03 '15 at 08:33
10

You may need to implement UIBarPositioningDelegate in your view Controller.

self.venueSearchController.searchBar.delegate = self;

The searchBar is looking for a response from it's delegate.

@protocol UISearchBarDelegate <UIBarPositioningDelegate> 

Add the following to your self (I assume it's a ViewController)

#pragma mark - <UIBarPositioningDelegate>

// Make sure NavigationBar is properly top-aligned to Status bar
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
{
    if (bar == self.venueSearchController.searchBar) {
        return UIBarPositionTopAttached;
    }
    else { // Handle other cases
        return UIBarPositionAny;
    }
}
Stephen Furlani
  • 6,586
  • 4
  • 27
  • 56
  • Great solution. I believe `UISearchController` doesn't pass enough information up the chain to help view controllers properly display the searchBar! Although we are injecting the searchBar right into tableView's header, but I guess it's most often than not the situation! and I guess they must be designed from that perspective. – M. Porooshani May 03 '15 at 05:20
1

I believe this may be an issue with the way UITableViewController layout deals with the navigation bar going as opposed to there being no navigation bar when it appears in the case of you rotating back.

I think you can solve this issue by replacing your UITableViewController with a UIViewController into which you drop a UITableView. Then set the top constraint of the table view to be the top layout guide. Set the side constraints to left, right, bottom of 0.

This should ensure that the table always stays below the status bar and will still move correctly when the nav bar goes and comes back.

See this discussion: iOS 7: UITableView shows under status bar

Community
  • 1
  • 1
Rory McKinnel
  • 7,730
  • 2
  • 15
  • 28
0

I've faced a similar issue with UISearchController using it with navigationItem. It looks differently, but caused by the very same problem: UISearchController does NOT update searchBar frame when status bar reappears.

But instead of manually adjusting frames of searchBar's view hierarchy you should simply force it to update layout by toggling hidesNavigationBarDuringPresentation back and forth during rotation either in traitCollectionDidChange or viewWillTransition(to size: CGSize, with cooridnator: UIViewControllerTransitionCoordinator):

So the fix would look like this:

 override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    if #available(iOS 11, *) {
        navigationItem.hidesSearchBarWhenScrolling.toggle()
        navigationItem.hidesSearchBarWhenScrolling.toggle()
    }
}

And here is how the original issue looks like.

Search in landscape without status bar

Then rotating and got this:

Search in portrait after status bar reappearing

Arkadii
  • 658
  • 4
  • 7
-6

I've "fixed" this temporarily by turning off "Hide status bar" in settings.

enter image description here

aherrick
  • 18,488
  • 29
  • 100
  • 168