Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a search bar to the top of a UITableView

I have a UITableView and am currently working on adding a custom search bar at the top consisting of a UIView with a UITextField inside of it. As is standard for iOS apps, the search bar should only be visible when the table view is scrolled to the top — when scrolling down it should disappear off the screen along with the other cells.

However, I cannot figure out a way to achieve this effect. If I place the search bar at the top of the table view, it will overlay the cell beneath it. If I place it 50 pixels above the table view, it is not possible for the user to select it since it will automatically disappear when the user releases their finger from the screen.

Can someone please enlighten me as to how to achieve this effect?

like image 723
wstr Avatar asked Apr 04 '14 17:04

wstr


3 Answers

Usually you just use UISearchBar as a tableViewHeader for your table view. If you want it hidden when the user enters the screen (like it's done in most native apps) you can just set contentOffset for the tableView in viewWillAppear.
And I am pretty sure that's in fact how they do it. And if you think about it it's what tableHeaderView is meant for.

Try something like this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0., 0., 320., 44.)];
    self.tableView.tableHeaderView = searchBar;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    CGPoint contentOffset = self.tableView.contentOffset;
    contentOffset.y += CGRectGetHeight(self.tableView.tableHeaderView.frame);
    self.tableView.contentOffset = contentOffset;
}

Note that in iOS 7 you should not just set the contentOffset of your tableView to CGPointMake(0., CGRectGetHeight(self.tableView.tableHeaderView.frame)) if your viewController has automaticallyAdjustsScrollViewInsets set to YES, since it probably will not be CGPointZero in viewWillAppear:

like image 54
dariaa Avatar answered Sep 29 '22 03:09

dariaa


@dariaa's answer updated for Swift 3:

override func viewDidLoad() {
    super.viewDidLoad()
    let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 44))
    self.tableView.tableHeaderView = searchBar
}
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    var contentOffset: CGPoint = self.tableView.contentOffset
    contentOffset.y += (self.tableView.tableHeaderView?.frame)!.height
    self.tableView.contentOffset = contentOffset
}

Though you'll probably need to set the searchBar as a property if you want to use it.

like image 21
davidrynn Avatar answered Sep 29 '22 04:09

davidrynn


If you only want your search to be visible when the UITableView is scrolled all the way to the top, make a UITableViewCell subclass that houses your UISearchBar. Then, in tableView:cellForRowAtIndexPath, check if the indexPath is (0,0). This is the table view telling you it is creating the cell at the very top, so then just create your search bar cell instead of your default cell.

Code would look something like this:

- (void)viewDidLoad
{
     [self.tableView registerClass:[SearchBarCell class] forCellReuseIdentifier:@"SearchBarCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0 && indexPath.section == 0) {
        //this is the cell that displays the UISearchBar
        SearchBarCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchBarCell"];
        return cell;
    }
    else {
        //create your usual table view cell normally
    }
}

There may be a cleaner way to determine the row and section of the indexPath, but I'm writing this code off the top of my head and don't recall a better way.

like image 30
seankellycs Avatar answered Sep 29 '22 03:09

seankellycs