5

I'm looking to duplicate how the Facebook Messenger app shows the UISearchBar. When you tap the leftBarButtonItem in the navigationBar, the UISearchBar appears/animates from the top of the screen down, and when you cancel, it simply disappears upwards where it originated from.

I used to have my UISearchBar as the default setup in my table view's header (in storyboard), but now I'm wanting to do what I stated above but I am not sure where to begin. My search displayer controller is still in my storyboard, but I have deleted the searchBar from the tableView controller in the storyboard.

I appreciate any help offered!

klcjr89
  • 5,862
  • 10
  • 58
  • 91

3 Answers3

4

Omitting detail of my own project where I make the same thing it looks as follows:

static CGFloat searchBarHeight = 64.0;

@implementation
{
    NSArray *_tableData; // active list of data to show in table at the moment
    NSMutableArray *_filteredContacts; // filtered list while search is active
    NSArray *_allContacts; // initial list of all data without search
    UIView* _searchBarWrapper;
    UIView *_shadowView;
    UISearchBar *_searchBar;
}

- (void)loadView
{
    [super loadView];

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(showSearchBar:)];

    _searchBarWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, -searchBarHeight, self.navigationController.view.bounds.size.width, searchBarHeight)];
    _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 20.0, _searchBarContainer.bounds.size.width, searchBarHeight - 20.0)];
    [_searchBarContainer addSubview:_searchBar];
    [self.navigationController.view addSubview:_searchBarContainer];

    _shadowView = [[UIView alloc] initWithFrame:self.navigationController.view.bounds];
    _shadowView.backgroundColor = [UIColor blackColor];
    _shadowView.alpha = 0;
    [self.navigationController.view addSubview:_shadowView];
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideSearchBar:)];
    UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideSearchBar:)];
    [_shadowView addGestureRecognizer:tapGesture];
    [_shadowView addGestureRecognizer:swipeGesture];

    //_searchController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
    //_searchController.delegate = self;
    //_searchController.searchResultsDataSource = self;
    //_searchController.searchResultsDelegate = self;
}

- (void)showSearchBar:(id)sender
{
    [_searchBar becomeFirstResponder];
    [UIView animateWithDuration:0.25 animations:^{
        _searchBarWrapper.center = CGPointMake(_searchBar.center.x, searchBarHeight/2.0);
        _shadowView.alpha = 0.5;
    }];
}

- (void)hideSearchBar:(id)sender
{
    _searchBar.text = nil;
    [_tableView reloadData];

    [UIView animateWithDuration:0.25 animations:^{
        _searchBarWrapper.center = CGPointMake(_searchBar.center.x, -searchBarHeight/2.0);
        _shadowView.alpha = 0.0;
    }];
    [_searchBar resignFirstResponder];
    [_tableView reloadData];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    _tableData = _searchBar.isFirstResponder ? _filteredContacts : _allContacts;

    ....................
}


- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if (searchText.length) {

        _filteredContacts = ....;

        _shadowView.alpha = 0.0;
        [_tableView reloadData];
    }
    else {
        _shadowView.alpha = 0.5;
    }
}

- (void)searchBarCancelButtonClicked:(UISearchBar*)searchBar
{
    [self hideSearchBar:searchBar];
}

Note: The general behavior of this construction is analogous to UISearchDisplayController, the only difference is that we use the same table to show all results and filtered result. Also we need artificial shadow view.

It was my initial code and its behavior coincides with FB People view controller. After your comment I wrote standard UISearchDisplayController embedding but after commented it out because it breaks desired UI. It is impossible to change its animation behavior.

malex
  • 9,874
  • 3
  • 56
  • 77
  • Can you please show where your searchBarDisplayController and it's respective search bar code goes? – klcjr89 Jan 19 '14 at 21:18
  • Actually you don't even need hideSearchBar. SearchDisplayController does all for hide. – malex Jan 19 '14 at 21:57
  • I will try this later tonight. And don't worry, I will accept your answer if it works for me. – klcjr89 Jan 19 '14 at 22:14
  • Please look through my extended answer. – malex Jan 19 '14 at 22:44
  • I can't figure it out, mostly because of the undeclared variable: _searchBarContainer – klcjr89 Jan 20 '14 at 04:03
  • It doesn't look right, the cancel button isn't showing on my search bar. See pic here: http://i.imgur.com/mehx5Cm.png – klcjr89 Jan 20 '14 at 04:54
  • You need to set BOOL property to YES to show cancel button in definition of searchbar – malex Jan 20 '14 at 04:56
  • Ok i got that part working, however by setting the tint color and barTintColor properties, the cancel button is not the right color. self.searchBar.tintColor = [UIColor colorWithRed:16.0/255.0 green:100.0/255.0 blue:230.0/255.0 alpha:1.0]; self.searchBar.barTintColor = [UIColor colorWithRed:244.0/255.0 green:244.0/255.0 blue:244.0/255.0 alpha:1.0]; – klcjr89 Jan 20 '14 at 04:59
  • I'll write complete settings a bit later – malex Jan 20 '14 at 05:09
  • No problem, you're helping me very much. – klcjr89 Jan 20 '14 at 05:09
  • Ok I just figured out how to fix the tint colors myself. The only remaining issue now is that the search bar needs to go down 20 pixels. See pic: http://i.imgur.com/7LvgN6f.png – klcjr89 Jan 20 '14 at 05:29
  • It seems that we use different auto layout settings in iOS7. Try to set 40pt offset for searchBar: _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 40, _searchBarContainer.bounds.size.width, SEARCHBAR_HEIGHT - 40)]; – malex Jan 20 '14 at 06:02
  • I figured it out after playing around with the searchBar's layer and blending it in to the view. I will post your bounty in 3 hours or so. Thanks! – klcjr89 Jan 20 '14 at 17:04
  • OK hope you've got you wanted! – malex Jan 20 '14 at 21:11
4

Check out Apple's UICatalog sample code. Basically just present your UISearchController modally and you get the dropdown animation for free.

Steve Moser
  • 7,647
  • 5
  • 55
  • 94
  • Oh man you are killing it. I'd like to add that setting `definesPresentationContext` to `false` makes the `navigationBar` not animate which looks great. – jbouaziz May 30 '17 at 15:39
0

It seems like Facebook hides the navigation bar and displays the Search Bar and Search Display Controller on top. Try hiding the navigation bar with [self.navigationController setNavigationBarHidden:YES animated:NO]; and presenting your Search Bar and Search Display as a childView of your tableView. (I assume you know how "Search Bar and Search Display Controller" object works)

Another way would be avoiding UITableViewController and adding a UITableView inside a UIViewController and hide the Search Bar under the Navigation Bar so when you hide the Navigation Bar, the Search Bar is visible.

You can also set the UISearchBar as the UINavigationBar's titleView as described here.

Community
  • 1
  • 1
Armin
  • 1,150
  • 8
  • 24