UISearchController:UITableView 的 Section Index 与 searchBar 重叠

UISearchController: Section Index of UITableView overlaps searchBar

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

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;

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

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

如果您使用的是 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];

然后在您的 table 视图控制器代码中,设置以下 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];

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

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

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

这实际上是将您的搜索控制器显示在主屏幕顶部而不是主屏幕内。这创建了一个设计 trade-off,因为您现在必须处理 2 个视图控制器的布局,而不仅仅是一个。但那是我可以接受的。

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

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

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

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

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

只需更改 sectionIndex 的背景颜色:

Swift:

    tableView.sectionIndexBackgroundColor = UIColor.clearColor()

最肮脏和最简单的解决方案(随心所欲地工作),只需创建第二个 tableView。赞(Swift 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[[=11=]] }
    }
    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()
}

我知道这是一个老问题,但我已经看到这个问题出现过几次了。除了上述解决方案之外,更简单的答案是创建一个具有原始边界的新 UIView,然后 iOS 不会缩小宽度以适应 table 索引。

即在 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