在搜索过程中,UITableViewCell详细信息显示按钮按钮太远了

eds*_*sko 10 uitableview uisearchbar ipad ios

我有 UITableViewController一个UISearchBar作为tableHeaderView它的tableView.我也UISearchDisplayController初始化了它UISearchBar作为它searchBarUITableViewController它的contentsController.到目前为止一切都很好,一切都近乎有效

问题是UITableView具有accessoryType设置的单元格UITableViewCellAccessoryDetailDisclosureButton.这是发生的事情:

  1. 首先,一切看起来应该如此:
    在此输入图像描述
  2. 用户点击内部UISearchBar.
  3. UISearchDisplayController创建主表顶部的黑色覆盖,并使得指数(如,sectionIndexTitlesForTableView)主表中消失的.
  4. 假设用户此时隐藏键盘(通过按下标准键盘上的iPad"隐藏键盘"按钮)
  5. 由于用户尚未输入任何内容UISearchBar,我们仍然可以看到主表,尽管在黑暗叠加层下面添加了UISearchDisplayController.
  6. 隐藏键盘会暴露更多主表,导致主表加载更多单元格.
  7. 现在问题是:由于这些单元格在主表的索引被隐藏时被加载,因此公开按钮显示得太偏右(至少与其他单元格相比).
    在此输入图像描述
  8. 此外,当用户现在取消搜索时,可能不会重新加载那些单元格,导致公开按钮显示在索引下面(现在再次可见).
    在此输入图像描述

我对如何解决这个问题感到茫然; 我能想到的唯一选择是找到与披露按钮相对应的UIView并手动移动它,但这看起来非常难看,只是因为即使发现UIView 需要一个讨厌的黑客.如何以更好的方式解决这个问题的任何建议将不胜感激!

最小的可运行示例

以下是一个最小的例子.只需启动一个新的XCode项目,仅启用ARC,iPad,并使用以下内容替换AppDelegate的内容.请注意,为了最小的例子,我强制主表重新加载其单元格searchDisplayController:willShowSearchResultsTableView,否则主表将缓存其单元格并且问题将不会显示(在我的实际应用程序中,主表格因其他原因重新加载其单元格,我不完全确定为什么 - 但当然主表可以随时重新加载单元格.)

要查看发生的问题,请运行代码,在搜索框中键入内容(您将看到"搜索结果0 .. 5"),然后取消搜索.现在,主表的公开按钮显示在索引的下方,而不是旁边.

以下是代码:

@interface AppDelegate ()

@property (nonatomic, strong) UITableViewController* mainTableController;
@property (nonatomic, strong) UISearchDisplayController* searchDisplay;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.

    UITableViewController* tableViewController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];

    UITableView* tableView = [tableViewController tableView];
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    [tableView setDataSource:self];
    [self setMainTableController:tableViewController];

    UISearchBar* searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 0, 44)]; // Width set automatically
    [tableView setTableHeaderView:searchBar];

    UISearchDisplayController* searchDisplay = [[UISearchDisplayController alloc] initWithSearchBar:searchBar
                                                                                 contentsController:tableViewController];
    [searchDisplay setSearchResultsDataSource:self];
    [searchDisplay setDelegate:self];
    [self setSearchDisplay:searchDisplay];

    [[self window] setRootViewController:tableViewController];

    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        return 26;
    } else {
        return 1;
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        return 10;
    } else {
        return 5;
    }
}

- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
    // The problem arises only if the main table view needs to reload its data
    // In this minimal example, we force this to happen
    [[[self mainTableController] tableView] reloadData];

    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"SearchCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

        [[cell textLabel] setText:[NSString stringWithFormat:@"%c%d", 'A' + [indexPath section], [indexPath row]]];
        [cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];

        return cell;
    } else {
        UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"SearchCell" forIndexPath:indexPath];

        [[cell textLabel] setText:[NSString stringWithFormat:@"Search result %d", [indexPath row]]];
        [cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];

        return cell;
    }
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (tableView != [[self searchDisplay] searchResultsTableView]) {
        return [NSArray arrayWithObjects:@"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z", nil];
    } else {
        return nil;
    }
}
Run Code Online (Sandbox Code Playgroud)

Tre*_*bor 1

如果您想模仿苹果自己的应用程序在这些情况下的行为方式,那么正确的做法是导致详细信息披露按钮在开始搜索时全部移至右侧,然后再次全部移回搜索完成。

我在您的示例中通过使用添加到代码reloadData中的两种方法调用主表视图,自己实现了这一点:UISearchDisplayDelegate

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    [[[self mainTableController] tableView] reloadData];
}

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
    [[[self mainTableController] tableView] reloadData];
}
Run Code Online (Sandbox Code Playgroud)

这将迫使您的详细披露视图重新定位,以考虑表格视图索引的可见性,从而使所有披露指示符的位置无论是否处于搜索模式下都保持一致。

更新

我尝试过用其他UISearchDisplayDelegate方法重新加载表视图,包括:

- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
- (void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView
Run Code Online (Sandbox Code Playgroud)

但是,这些会产生相当不和谐的效果,详细信息披露按钮的位置会突然跳跃,因此我建议使用前面所述的willBeginSearchwillEndSearch方法。