Reloading UITableView behind UISearchDisplayController

岁酱吖の 提交于 2020-01-01 02:28:49

问题


I've run into this really strange phenomenon that I can't quite figure out. I have a UITableViewController that manages a UITableView. Pretty simple. I also have a UISearchDisplayController for searching the contents of the table view. The searching functionality will be able to delete items of the content displayed by the table view. So if the user chooses to delete one of the items they found while searching, I want to not only reload the UISearchDisplayController's table view but also the UITableViewController's table view. When I do that, the sections of the regular table view pop out and display above the UISearchDisplayController. It's really quite strange. I think the best way to explain it is with an image:

If any of you know what could possibly be causing this problem or know a workaround, that would be fantastic.


回答1:


UPDATED AGAIN

As it turns out, if a table's header is reloaded in the background it pops in front of the search controller no matter what.

I solved this by disabling the fetchedResultsController (setting it to nil) and letting it load lazily again when needed when the search disappears.

UPDATED - Original answer below

In my case I'm using two fetchedResultsControllers one for the main tableview and one for the search.

I discovered that preventing animations when adding the section headers prevents this bug. So while searchDisplayController.active I simply disable the animation of the section change. see code below.

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    if (!self.reordering) {
        UITableView *myTableView = controller == __fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
        UITableViewRowAnimation animation;
        if (self.searchDisplayController.active) {
            animation = UITableViewRowAnimationNone;
        } else {
            animation = UITableViewRowAnimationFade;
        }

        switch(type)
        {
            case NSFetchedResultsChangeInsert:
                [myTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:animation];
                break;

            case NSFetchedResultsChangeDelete:
                [myTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:animation];
                break;
        }
    }
}

ORIGINAL ANSWER

The other answer doesn't actually work on it's own. The reason is, the header that is showing is not a header in the searchDisplayController's tableview. It's a header from the main tableview that for some reason is being added above the search table view in the view hierarchy.

I solved this problem by disabling updates to the main tableview while searchDisplayController.active = YES.

In my case I'm using a lazily loaded fetched results controller so I did it like this:

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {
    [self.tableView reloadData];
}

- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
    self.fetchedResultsController.delegate = nil;
    self.fetchedResultsController = nil;
}

However, I still have the problem that if I want to reloadData on the main tableview so it is seen in the background, the section headers still float in front of the darkened area.

Does anyone have a better solution for this? It seems like a legitimate bug for viewForHeaderInSection and titleForHeaderInSection when data is reloaded while covered by a UISearchDisplayController.

The simplest answer for me is to try and override the search view so you can't see the background table. But that takes away from the "Appleness" of the app.




回答2:


Our solution is to do the following. It has only been tested in iOS 7:

  1. In viewForHeaderInSection, return nil if self.searchDisplayController.active is YES
  2. In didHideSearchResultsTableView, call [self.tableView reloadData] to reload the headers when the search table disappears



回答3:


I ran into this recently as well...the approach I decided on was to queue updates to the main tableView in a suspended serial dispatch queue until the the UISearchDisplayController hides the searchResultsTableView. I would probably consider this a bug as the section headers should not show through the main tableView if the searchResultsTableView has taken over that layer.




回答4:


I solved this in iOS 7 by only reloading the visible rows in the underlying table.

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
   [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}



回答5:


Fixed it..

Add the following lines in viewDidLoad

searchDisplayController.searchResultsTableView.delegate = self;
searchDisplayController.searchResultsTableView.dataSource = self;

That fixed it for me...




回答6:


[self.searchDisplayController.searchResultsTableView reloadData];



回答7:


Because of using UITableViewController. self.view is a TableView in the UITableViewController and SearchDisplayController's ContainerView is added to the self.view of UITableViewController. Just use UIViewcontroller.




回答8:


My solution was to avoid reloading the table if search results were displaying, then reloading any time the search results were dismissed.

I had to set a symbolic breakpoint on UITableView reloadData to find all the calls to reload that were causing the section headers to redraw on top of the search table.




回答9:


Hopefully you've figured this out by now, but just in case someone stumbles across this question: this is probably happening because your UITableViewController is the data source/delegate for the search table as well as your main table. That is, presumably, you have the same UITableViewDelegate/DataSource methods executing for both table views, and you're returning the same section header for both tables. Make sure you're handling your search results table separately:

- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section {
    if (aTableView == [[self searchDisplayController] searchResultsTableView]) {
        return nil;
    }
    // Return a title appropriate for self.tableView here
}


来源:https://stackoverflow.com/questions/3647319/reloading-uitableview-behind-uisearchdisplaycontroller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!