25

I've set my UITableView row height to in Interface Builder to 54.0. I have a UISearchDisplayController on that view. When the user taps the search bar in it, the table resizes properly. However, when they start typing (and actually doing the search) the row height decreases. It stays wrong until the search taps Cancel.

I could find no documentation on this behavior on Apple's site.

I've tried setting the row height in UISearchDisplayDelegate delegate calls. This might be the right approach, but I don't know the details and couldn't get it to work.

I've also tried implementing - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;. This worked, but I have thousands of entries in this list and can't take the performance hit.

What's the right way to fix this?

Steven Fisher
  • 44,462
  • 20
  • 138
  • 192
  • I would encourage everyone to take a look at steven's answer below. His is the only answer that a) follows the `UITableViewDataSource` protocol, treating the `UISearchTableView` like any other table and b) Supports more than a single height for rows. B is rather important if you have standard functionality to display a customized "no search results" cell which typically will be sized to take the entire tableView frame. – memmons Sep 10 '13 at 22:04
  • I doubt that's true. I found implementing `heightForRowAtIndexPath` worked for me in that case, it was just slow for my table (which had tens of thousands of rows). Make sure you're not returning a variable height only for certain `tableView` parameters and you should be fine. – Steven Fisher Sep 10 '13 at 22:36
  • `heightForRowAtIndexPath` should never have a significant impact on `tableView` performance. Whether you have 10 rows or 10,000 rows, the tableView only deals with the currently visible rows. So, unless you are taking a significant chunk of time to determine what the row height should be, your tableView should be able to maintain a 60fps animation when scrolling. – memmons Sep 11 '13 at 15:10
  • That's not true. Per Apple's documentation: "Every time a table view is displayed, it calls tableView:heightForRowAtIndexPath: on the delegate for each of its rows, which can result in a significant performance problem with table views having a large number of rows (approximately 1000 or more)." – Steven Fisher Sep 11 '13 at 16:55

8 Answers8

56

The correct way to do this is to use the following delegate.

- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
    tableView.rowHeight = 54.0f; // or some other height
}

It's called when the UITableView is created or shown.

If you happen to call searchDisplayController.searchResultsTableView in other code when a search is not being performed, it will create the UITableView in advance. If you use the willShow delegate method to set the rowHeight, it will miss the timing (for some reason) to change the rowHeight if the tableView has been created beforehand.

Christopher Rogers
  • 6,759
  • 1
  • 22
  • 13
16

I found it!

Assuming the table is stored in tableView:

- (void)viewDidLoad;
{
    [super viewDidLoad];
    self.searchDisplayController.searchResultsTableView.rowHeight = tableView.rowHeight;
}

Nothing else is necessary.

Edit: See netmikey's answer for a better solution.

Steven Fisher
  • 44,462
  • 20
  • 138
  • 192
10

Steve, your solution didn't work for me: The first time the search result would display fine, but when a user was hitting "Cancel" (closing away the search bar) and then reopening it and entering a search term into it, the height would be wrong again.

DigDog's solution of using searchDisplayController:didShowSearchResultsTableView was kinda working, but users saw the cell height "jumping" when the search started.

The solution I found, that fixed both these issues is using:

- (void)searchDisplayController: (UISearchDisplayController *)controller 
 willShowSearchResultsTableView: (UITableView *)searchTableView {

    searchTableView.rowHeight = myTableView.rowHeight;
}

... in the UISearchDisplayDelegate.

Regards, netmikey

netmikey
  • 2,422
  • 2
  • 28
  • 35
3

In viewDidLoad:

you can set the search display controller's delegate to self:

- (void)viewDidLoad 
{
    self.searchDisplayController.delegate = self;
}

Then, implement the table view delegate in your view controller:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableview == self.searchDisplayController.tableView) {
        return 55;
    } else if (tableView == self.tableView) {
       return  44;
     }
}
stephen
  • 1,617
  • 3
  • 20
  • 27
  • I can't +1 this enough. This is the only answer that a) follows the `UITableViewDataSource` protocol, treating the `UISearchTableView` like any other table and b) Supports more than a single height for rows. B is rather important if you have standard functionality to display a customized "no search results" cell which typically will sized to take the entire tableView frame. – memmons Sep 10 '13 at 22:02
1

Overriding the method didLoadSearchResultsTableView should do the trick.

- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
    tableView.rowHeight = 82.0; // Change height of search result row
}

More explanation from this blog

Andy
  • 5,287
  • 2
  • 41
  • 45
0

I've been using ios 7.0 and Xcode 5.0. I think you should change you row height in this method:

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    // Return the number of rows in the section.
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
        tableView.rowHeight = ...;// change your row height here!
        return [self.searchResults count];
    }
    else
    {
        ...
        return ...;
    }
    }

Because every time a tableview try to display its layout, this method is called, so everytime you type a letter into search bar, this method is called,and the row height won't have a chance to change.

little pig
  • 31
  • 1
0

You need to set both

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    
    return 54.;
}

and

self.tableView.rowHeight = 54.;

also in your UISearchDisplayDelegate

- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView {
    tableView.rowHeight = 54.; 
}

Otherwise, when "No Result" happened in searching, cell height will fall back to default.

digdog
  • 4,198
  • 1
  • 26
  • 23
  • Actually, heightForRowAtIndexPath: and .rowHeight behaves a little differently (at least in your case), so make sure you set them both, not just one of them. – digdog Apr 14 '10 at 18:05
  • I can't use heightForRowAtIndexPath. With 20,000 rows it slows down the table far too much on a real device. – Steven Fisher Apr 14 '10 at 18:35
-1

None of the solutions worked for me...

Did my own hit and trial... and got it working...

If you want different row heights for normal & search table views...

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
// for normal results
     if (tableView==self.tableView) return 54;
// for search results
     else return 54; }

And if you want common height...

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
     return 54; }

PS: Do keep in mind, if you have same row height for each row, this method is not very efficient resource usage wise, as the row height is re-calculated for each cell... Although, this is unnoticeable in most cases, I am still searching for a better solution!

BufferStack
  • 549
  • 9
  • 20