简体   繁体   中英

UISearchController: Section Index of UITableView overlaps searchBar

I'm building an iOS 8 app that uses the new UISearchController. In the table view related to the search controller, I'm using a section index to let users jump quickly from one section of the table to the next. It's working just fine, but the section index overlaps the search bar on the table / search controller. Has anyone run into this issue before and, if so, how did you solve it? Below is how I'm initializing my search controller:

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;

在此输入图像描述

just change background color of sectionIndex:

Swift:

    tableView.sectionIndexBackgroundColor = UIColor.clearColor()

I know this is an old question, but I've seen this come up a couple of times.. Instead of the above solutions the easier answer is to create a new UIView with the original bounds and then iOS does not shrink the width to accommodate the table index.

Ie in 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

I've had similar concerns building a table view that includes a search bar.

Try changing the appearance of the following properties... this may help you find a suitable solution.

If you're using Interface Builder / Storyboard, in the Attribute Inspector set your search bar with the following properties:

  • Search Style = Minimal
  • Bar Style = Default
  • Translucent = YES
  • Bar Tint = Default

故事板属性检查器

These properties can of course be set in code:

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];

Then in your table view controller code, set the following UITableView properties:

//  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];

This combination provides a more acceptable appearance in my opinion, and I use this in my apps that use table views with search bars.

Finally came up with an acceptable solution to this question. This answer builds off of my question above (I'm using all the same code minus what is changed here). The main thing to note here is that @andrewbuilder was right - adding the search bar as a table header view will guarantee that the search bar will move on scroll; it's just acting like any other table header view.

What I ended up doing was a combination of things. The main change I made in my approach was changing the way my main controller presents my search controller. Specifically, I went from self.definesPresentationContext = YES; to self.definesPresentationContext = NO;

What this does is essentially presents your search controller on top of your main screen rather than within it. This creates a design trade-off in the fact that you now have to deal with the layout of 2 view controllers rather than just one. But that was something I was ok with.

The next thing I did was create a strong pointer to a UISearchBar in my main view controller, which I called searchBar . Then, I set that property to be equal to my search controller's searchBar and added it to my subview like so:

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

In order to get this to look right, I had to make sure my table's x position was equal to the bottom of the search bar's frame. You can do that in many ways: either in code, in Interface Builder, or with a combination of both. I'll leave you to figure out the right choice for yourself.

Again, the tradeoff here is that you have to set up two view controllers and make it look like it's the same screen even though it's not (customizing the nav bar, handling segues, etc). This seems to be a necessary evil that me and my team were willing to accept. From here, the next steps in getting this all working was messing with the edgesForExtendedLayout property on both view controllers (as well as the contentInset of the table views). I'm not going to write that code here since it will probably be different for everyone depending on their design. However, that's the gist of it.

Please feel free to add to this thread if you find a simpler solution. I searched far and wide, but with UISearchController being a very new control, there's not a lot of documentation / info on it (and its quirks).

Most dirty and simple solution(works as you wish), just create second tableView. Like(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])

and

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
}

and for example

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM