Search code examples
iosuinavigationbaruisearchbaruisearchcontroller

How to replace the navigation bar with an UISearchBar?


I would like to replace the navigation bar with the search bar once shown and back.

OR

I would be fine if the navigation bar always laps over the content of my main view controller.


I set up the search controller like that:

_searchController = [[UISearchController alloc] initWithSearchResultsController:[[MySearchViewController alloc] init]];
_searchController.delegate = self;
_searchController.obscuresBackgroundDuringPresentation = TRUE;
_searchController.hidesNavigationBarDuringPresentation = TRUE;
_searchController.searchBar.placeholder = @"Search...";
_searchController.searchBar.delegate = self;

I show the search controller like that:

- (void)searchButtonTapped:(id)sender
{
  self.navigationItem.searchController = _searchController;
  [self.navigationController.view setNeedsLayout];
  [self.navigationController.view layoutIfNeeded];
  [self.navigationItem.searchController.searchBar becomeFirstResponder];
}

I hide the search controller like that:

- (void)willDismissSearchController:(UISearchController*)searchController
{
  self.navigationItem.searchController = nil;
  [self.navigationController.view setNeedsLayout];
}

I know there is the property searchController.hidesNavigationBarDuringPresentation which is close to what I want but exactly. Because the navigation bar only hides once I enter the search bar but I want it to hide already when I present the search bar.

As soon as I press the search icon button in the navigation bar it should be replaced with the search controller and only the search bar is being visible at the top. Does anyone know how to achieve this?


I already tried:

  • to hide the navigation bar when I show the search controller with [self.navigationController setNavigationBarHidden:YES animated:NO];
  • to control the search bar height constraint and change it according visibilty
  • to set the search controller to the navigationItem.titleView -> it's not what I want
  • to hide the search controller according visivility -> the navigation bar remains with the same height only the search controller is hidden
  • to use self.definesPresentationContext but this seems a different setting to what I need
  • had a look into self.navigationItem.hidesSearchBarWhenScrolling but this does not apply since I don't use a table view controller

Solution

  • I could make my first option to

    I would like to replace the navigation bar with the search bar once shown and back.

    work.

    I used the approach to show and hide the left and right bat button items of the navigation item when the UISearchBar is being shown.

    I would be interested if there is a simpler way to achieve the same?

    @interface MyViewController() <UISearchControllerDelegate, SearchDelegate>
    @end
    
    @implementation MyViewController
    {
      UIView*                    _navigationItemTitleView;
      NSArray<UIBarButtonItem*>* _leftBarButtonItems;
      NSArray<UIBarButtonItem*>* _rightBarButtonItems;
    }
    
    - (void)viewDidLoad
    {
      _searchController        = [[UISearchController alloc] initWithSearchResultsController:[[MySearchViewController alloc] init]];
      // ....
      _navigationItemTitleView = self.navigationItem.titleView;
      _leftBarButtonItems      = self.navigationItem.leftBarButtonItems;
      _rightBarButtonItems     = self.navigationItem.rightBarButtonItems;
    }
    
    - (void)searchButtonTapped:(id)sender
    {
      // show the search bar in the navigation item
      self.navigationItem.leftBarButtonItems  = nil;
      self.navigationItem.rightBarButtonItems = nil;
      self.navigationItem.titleView = _searchController.searchBar;
      _searchController.active = TRUE;
    }
    
    - (void)willDismissSearchController:(UISearchController*)searchController
    {
      // hide the search bar and restore previous state of the navigation item
      self.navigationItem.leftBarButtonItems  = _leftBarButtonItems;
      self.navigationItem.rightBarButtonItems = _rightBarButtonItems;
      self.navigationItem.titleView           = _navigationItemTitleView;
    }