UISearchController:UITableView 的 Section Index 与 searchBar 重叠

Posted

技术标签:

【中文标题】UISearchController:UITableView 的 Section Index 与 searchBar 重叠【英文标题】:UISearchController: Section Index of UITableView overlaps searchBar 【发布时间】:2015-03-06 19:33:14 【问题描述】:

我正在构建一个使用新 UISearchController 的 ios 8 应用程序。在与搜索控制器相关的表格视图中,我使用了一个部分索引来让用户从表格的一个部分快速跳转到下一个部分。它工作得很好,但是部分索引与表/搜索控制器上的搜索栏重叠。以前有没有人遇到过这个问题,如果有,你是如何解决的?下面是我如何初始化我的搜索控制器:

self.resultsTableController = [self.storyboard instantiateViewControllerWithIdentifier:[SelectSpecialtySearchResultsTVC storyboardId]];
UINavigationController *searchResultsNavController = [[UINavigationController alloc]initWithRootViewController:self.resultsTableController];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsNavController];

self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.barTintColor = [UIColor colorWithHexString:kColorGrayLight];
self.searchController.searchBar.translucent = NO;
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, [self.view bounds].size.width, 44.0);
self.searchController.searchBar.delegate = self;

self.tableView.tableHeaderView = self.searchController.searchBar;

//present the search display controller within the confines of this class's table view
self.definesPresentationContext = YES;

// we want to be the delegate for our filtered table so didSelectRowAtIndexPath is called for both tables
self.resultsTableController.tableView.delegate = self;
self.searchController.delegate = self;

【问题讨论】:

我怀疑这与您正在实例化搜索栏并将其添加到表头视图这一事实有关,因此它的作用与任何其他表头一样。您希望搜索栏保持在视图顶部,还是在用户向下滚动表格时消失? 搜索栏目前随着用户滚动而消失,我相信这是我的团队想要的行为。 在您发表评论之后再考虑一下。如果它可以帮助我摆脱重叠索引,那么让搜索栏保持在滚动的顶部对我来说很好。我正在修补将栏添加为单独的视图(在表格之外),但还没有提出一个成功的解决方案。 【参考方案1】:

只需更改 sectionIndex 的背景颜色:

斯威夫特:

    tableView.sectionIndexBackgroundColor = UIColor.clearColor()

【讨论】:

【参考方案2】:

我知道这是一个老问题,但我已经看到这个问题出现了好几次了。而不是上述解决方案,更简单的答案是创建一个具有原始边界的新 UIView,然后 iOS 不会缩小容纳表格索引的宽度。

即在 viewDidLoad 中

let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: searchController.searchBar.bounds.size.height))
headerView.addSubview(searchController.searchBar)
tableView.tableHeaderView = headerView

【讨论】:

【参考方案3】:

我在构建包含搜索栏的表格视图时也有类似的担忧。

尝试更改以下属性的外观...这可能会帮助您找到合适的解决方案。

如果您使用的是 Interface Builder / Storyboard,请在属性检查器中为您的搜索栏设置以下属性:

搜索样式 = 最小 条形样式 = 默认 半透明 = 是 条形色调 = 默认

这些属性当然可以在代码中设置:

self.searchController.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchController.searchBar.barStyle = UIBarStyleDefault;
self.searchController.searchBar.translucent = NO;
//  By not setting the barTintColor property, it remains default
//  self.searchController.searchBar.barTintColor = [UIColor yourColor];

然后在您的表格视图控制器代码中,设置以下UITableView 属性:

//  Prepare custom colours as needed
UIColor *brightBlueColour = [UIColor colorWithRed:0.40 green:0.90 blue:1.00 alpha:1.00];

//  Set section index properties for your table view
[yourTableView setSectionIndexColor:[UIColor brownColor]];
[yourTableView setSectionIndexTrackingBackgroundColor:[UIColor brightBlueColor]];
if ([yourTableView respondsToSelector:@selector(sectionIndexBackgroundColor)])
    [yourTableView setSectionIndexBackgroundColor:[UIColor clearColor]];

//  Set additional properties for background colour
CGRect frame = self.tableView.bounds;
frame.origin.y = -frame.size.height;
UIView *viewBackground = [[UIView alloc] initWithFrame:frame];
[viewBackground setBackgroundColor:self.brightBlueColour];
[yourTableView addSubview:viewBackground];

在我看来,这种组合提供了更容易接受的外观,我在使用带有搜索栏的表格视图的应用程序中使用它。

【讨论】:

感谢您的回答。设置 sectionIndexBackgroundColor 是一个不错的小技巧,但我认为您关于使搜索栏成为超级视图而不是表头视图的一部分的第一个建议更接近我正在寻找的内容。仍然无法确定该选项,但这是一条不错的选择。 不幸的是,目前还没有很多关于 UISearchController 的教程,而且那些没有使用部分索引的教程(因此他们没有面对或解决这个问题) .由于我的目标是 iOS 8,我不想回滚到 UISearchDisplayController。 我会更新我的答案,但可能不会在 12 小时左右。同时考虑视图层次结构以及您希望搜索栏位于其中的位置。使用带有这个或另一个测试项目的故事板来帮助可视化该层次结构。另外值得注意的是,从 iOS 7 开始,您可以将搜索栏滚动到屏幕顶部的导航栏中。 我绝对希望视图层次结构遵循您在第一条评论中布置的路径,表格视图和搜索栏是两个不同的子视图,以便部分索引的大小合适并且不会'不要重叠搜索栏。但是,当我尝试这样做时遇到的问题是搜索控制器及其搜索栏无法正常工作。 Brian 我建议您阅读this answer 我前段时间写过...这有点离题但可能会提供一些想法和/或帮助您了解实例化所需的代码级别在代码中查看所有内容。我目前正在努力将我的应用程序更新为UISearchController,所以我还在学习自己。【参考方案4】:

终于为这个问题想出了一个可以接受的解决方案。这个答案建立在我上面的问题之上(我使用所有相同的代码减去此处更改的代码)。这里要注意的主要一点是@andrewbuilder 是正确的——将搜索栏添加为表头视图将保证搜索栏将在滚动时移动;它就像任何其他表头视图一样。

我最终做的是多种事情的结合。我在方法中所做的主要改变是改变了我的主控制器呈现我的搜索控制器的方式。具体来说,我从self.definesPresentationContext = YES; 转到self.definesPresentationContext = NO;

这实际上是将您的搜索控制器显示在主屏幕顶部,而不是在其中。这会在设计上进行权衡,因为您现在必须处理 2 个视图控制器的布局,而不仅仅是一个。但那是我可以接受的。

接下来我在我的主视图控制器中创建了一个指向UISearchBar 的强指针,我称之为searchBar。然后,我将该属性设置为等于我的搜索控制器的 searchBar 并将其添加到我的子视图中,如下所示:

self.searchBar = self.searchController.searchBar;
[self.view addSubview:self.searchBar];

为了使它看起来正确,我必须确保我的表格的 x 位置等于搜索栏框架的底部。您可以通过多种方式做到这一点:在代码中、在 Interface Builder 中或两者的结合。我会让你自己找出正确的选择。

同样,这里的权衡是您必须设置两个视图控制器并使其看起来像是同一个屏幕,即使它不是(自定义导航栏、处理转场等)。这似乎是我和我的团队愿意接受的必要邪恶。从这里开始,让这一切正常工作的下一步是弄乱两个视图控制器上的edgesForExtendedLayout 属性(以及表视图的contentInset)。我不打算在这里编写该代码,因为每个人的设计可能会有所不同。然而,这就是它的要点。

如果您找到更简单的解决方案,请随时添加到此线程。我进行了广泛的搜索,但UISearchController 是一个非常新的控件,没有很多文档/信息(及其怪癖)。

【讨论】:

【参考方案5】:

最肮脏和简单的解决方案(如你所愿),只需创建第二个 tableView。喜欢(斯威夫特 3):

    tableView = UITableView(frame: CGRect.zero, style: .grouped)
    tableView.delegate = self
    tableView.dataSource = self
    tableView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(tableView)
    let cnt1 = NSLayoutConstraint(item: tableView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0)
    let cnt2 = NSLayoutConstraint(item: tableView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0)
    let cnt3 = NSLayoutConstraint(item: view, attribute: .trailing, relatedBy: .equal, toItem: tableView, attribute: .trailing, multiplier: 1, constant: 0)
    let cnt4 = NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: tableView, attribute: .bottom, multiplier: 1, constant: -1)
    constraintTableViewBottom = cnt4
    view.addConstraints([cnt1, cnt2, cnt3, cnt4])

    let tableView2 = UITableView(frame: CGRect.zero, style: .grouped)
    tableView2.sectionIndexColor = .black
    tableView2.sectionIndexBackgroundColor = .clear
    tableView2.delegate = self
    tableView2.dataSource = self
    tableView2.translatesAutoresizingMaskIntoConstraints = false
    tableView2.backgroundColor = .clear
    view.addSubview(tableView2)
    let cnt5 = NSLayoutConstraint(item: tableView2, attribute: .height, relatedBy: .equal, toItem: view, attribute: .height, multiplier: 1, constant: 0)
    let cnt6 = NSLayoutConstraint(item: tableView2, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0)
    let cnt7 = NSLayoutConstraint(item: view, attribute: .trailing, relatedBy: .equal, toItem: tableView2, attribute: .trailing, multiplier: 1, constant: 0)
    let cnt8 = NSLayoutConstraint(item: tableView2, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 13)
    tableView2.addConstraint(cnt8)
    view.addConstraints([cnt5, cnt6, cnt7])

func sectionIndexTitles(for tableView: UITableView) -> [String]? 
    if tableView == self.tableView  return nil 
    if searchController.isActive && searchController.searchBar.text != "" 
        return filteredCells.keys.map  return sections[$0] 
    
    return sections


func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int 
    self.tableView.scrollToRow(at: IndexPath(row: 0, section: index), at: .top, animated: true)
    return sections.index(of: title)!


final func numberOfSections(in tableView: UITableView) -> Int 
    if tableView != self.tableView  return 0 
    return sections.count

例如

final func updateSearchResults(for searchController: UISearchController) 
    filterCells(searchText: searchController.searchBar.text!)
    tableView.reloadSectionIndexTitles()

【讨论】:

以上是关于UISearchController:UITableView 的 Section Index 与 searchBar 重叠的主要内容,如果未能解决你的问题,请参考以下文章

UISearchController 与单元格布局混淆

UISearchController 未显示

UISearchController 没有响应

UISearchController 保留问题

UISearchController:searchResultsController 不显示

UISearchController + UICollectionView 错误