SearchBar in TableViewController - ios

In my app I have a UITableViewController, and I want to add a searchbar to it. The tableview has 3 sections which expand when clicked on one of them. I added this code to viewDidLoad:
searchBar.showsScopeBar = true
searchBar.delegate = self
searchBar.frame = CGRectMake(0, 0, tableView.frame.size.width, 100)
self.view.addSubview(searchBar)
The problem is: the searchbar appears in the first section when you open it, and it should appear above the whole tableview, any suggestions?
Any help is appreciated!

You can add searchBar as a tableHeaderView of the TableView of your UITableViewController.

You can find pretty helpful example in Programming iOS 9 by Matt Neuburg, inside chapter II: Table Views and Controller Views.
let src = SearchResultsController(data: self.sectionData)
let searcher = UISearchController(searchResultsController: src)
self.searcher = searcher
searcher.searchResultsUpdater = src
let b = searcher.searchBar
b.sizeToFit() // crucial, trust me on this one
b.autocapitalizationType = .None
self.tableView.tableHeaderView = b
self.tableView.reloadData()
self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition:.Top, animated:false)
He also warns, that adding search bar as the table view's header view may have an odd effect: it causes the table view's background color to be covered by an gray color, visible above the search bar when the user scrolls down. The official workaround is to assign the table view a backgroundView with the desired color.

Related

Custom position for UISearchBar

I'm currently trying to implement UISearchController and its associated UISearchBar.
I aim to have a UISearchBar just above my UITableView which goes top as soon as it has the focus, like the picture below (screenshot from my old UI with UISearchDisplayController, now deprecated):
I already tried to set my UISearchBar as header of the UITableView, it works well but I have 2 issues :
The search bar logically scrolls with the table view content
When the search bar takes the focus, it remains at the same position
Here is the way I configured my UISearchBar:
func configureSearchController() { // Method called in the viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
searchController!.searchResultsUpdater = self
searchController!.dimsBackgroundDuringPresentation = false
searchController!.searchBar.placeholder = "searchfood.searchbar.placeholder".localized
searchController!.searchBar.sizeToFit()
searchController!.hidesNavigationBarDuringPresentation = false
print(searchController!.searchBar.frame)
// Place the search bar view to the tableview headerview.
foodsTableView.tableHeaderView = searchController!.searchBar
// Search bar
searchController!.searchBar.searchBarStyle = .prominent
searchController!.searchBar.barTintColor = ColorLSDP.corail
searchController!.searchBar.tintColor = ColorLSDP.beige
}
So I tried to remove the following lines:
foodsTableView.tableHeaderView = searchController!.searchBar
But when I did this, I was not able to see the UISearchBar anymore.
After checking some other SO topics, I just spotted that my UISearchBar was maybe hidden below my UINavigationBar. So I tried to add the following lines in the viewDidLoad() method:
self.navigationController?.navigationBar.isTranslucent = false
self.edgesForExtendedLayout = []
It changed nothing.
Anyway, it did not solve my main issue which is having this search bar initially positioned like the screenshot above.
Is there a way to do this properly with the brand new UISearchController ?
Thanks a lot for your upcoming answers,
Regards,
Seb R.

Incorrect scrollview insets when Adjust Scroll View Insets is true after orientation changes

My project is storyboard based and includes the following controllers:
UINavigationController.
UITableViewController - TableViewController which contains a list of items.
UIViewController - ViewController which displays details of the item selected in TableViewController.
There's a UISearchController inside TableViewController, with its searchBar set as the tableHeaderView of the tableView. The gist of TableViewController is here:
class TableViewController: UITableViewController {
private let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchBar.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
}
}
I've checked (in fact, haven't unchecked) the Adjust Scroll View Insets in the Interface Builder for TableViewController.
When the user taps on an item in the list, it's segueing to the ViewController with the detailed information about the item.
Everything works smoothly in most cases, and TableViewController is displayed as expected:
The issue arises when the user changes orientation in ViewController and then segues back to TableViewController. The latter in this case has incorrect content inset set for its 'tableView':
If the search is cancelled before tapping an item the issue is not present.
Recording of the issue on an iOS 9 simulator: https://vimeo.com/182953863.
To make sure there's something wrong with content inset of the table view, I printed the inset in the viewDidLayoutSubviews method of TableViewController. Here's the output:
// Normal mode
UIEdgeInsets(top: 64.0, left: 0.0, bottom: 0.0, right: 0.0)
// After orientation changes in ViewController
UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
There're a number of similar questions on SO (1, 2, 3), from which I made two conclusions:
If the view controller added is a UITableViewController, the issue should not be appeared since Apple will auto padding it (answer). This is the case, and the issue still appears.
Try switching off the autoAdjustScrollViewInsets and set the insets manually in the code. This one should definitely work, but I'd like to first find the culprit of the issue.
What I've tried to do:
Set hidesNavigationBarDuringPresentation to true. The issue persisted.
Set definesPresentationContext to false, and calling self.view.endEditing(true) in the prepareForSegue of TableViewController (this one had no effect). The issue was gone. But the search bar persisted down the hierarchy of the view controllers, namely in ViewController, which was not acceptable.
Resigning first responder for the search bar in prepareForSegue by searchController.searchBar.resignFirstResponder(). The issue persisted.
I've assembled a test project which reproduces this issue. The search doesn't work and the list items are hard-coded, but it does reproduce the issue without extra details.
There must be an error in the way I set up the search controller, but I couldn't find it.

Tapping in the UISearchBar causing table contents to shift down, and periodically the searchbar itself will move

My search is working perfectly, however when I first tap into the searchbar the cells from the tableview it is attached to will visibly shift down revealing the 'pull to refresh'. I am using a separate search controller as the search is reused in other views.
self.searchController = UISearchController(searchResultsController: self.resultsController)
self.searchController.searchResultsUpdater = self.resultsController
self.searchController.searchBar.placeholder = "Type symbol or company ..."
self.searchController.searchBar.barTintColor = UIColor(red: 12, green: 26, blue: 29, alpha: 1.0)
self.searchController.searchBar.barStyle = UIBarStyle.Black
self.searchController.hidesNavigationBarDuringPresentation = false
self.resultsController.searchBar = self.searchController.searchBar
tableView.tableHeaderView = self.searchController.searchBar
Note self.resultsController is a custom UITableViewController with appropriate methods and an extension for the results updater.
Can anyone tell me what would cause this sort of behaviour and how I can correct it?
Here are some screens to help illustrate the issue:
The interesting thing is that if I navigate to another view, or refresh the initial tableview. The layout corrects itself, and the search behaves exactly as intended.
I tried numerous solutions, but noting the behaviour above. Once you activated search, then navigated to another view. Any subsequent access of the search it was positioned correctly.
I moved my search code into the viewWillAppear method in my table view controller and vola. It works perfectly.
I suspect this has to do with the fact that my layout is
TabController -> NavigationController -> TableviewController
Put the following line in viewDidLoad solved the problem for me:
self.definesPresentationContext = false

Empty space at the bottom of UITableView after adding UISearchBar

I'm making a UITableView that displays a record of past events. It all looked great until I added a search bar at the top. It all looks how I want when it's scrolled to the top:
However, when I scroll to the bottom there's now a bunch of white space. It's hard to tell in this screenshot as there's no screen border but the tableview scroll will rest on this screen with about half the page blank:
Interestingly, when I activate the search bar at all (i.e. click in it and then press cancel) the white space goes away until this view appears again.
I've tried all sorts of settings for the tableView as well as using reloadData() at various stages of the view layout process to no avail. I know the number of rows is correct. The only thing I've found to make the white space go away is to disable the search bar. But I want the search bar!
Here's the code for the search bar:
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.searchBar.placeholder = "Search by keyword, name, etc."
controller.searchBar.barTintColor = UIColor(red: 224/256, green: 244/256, blue: 255/256, alpha: 1)
controller.searchBar.delegate = self
self.pastServicesTable.tableHeaderView = controller.searchBar
return controller
})()
Same thing happened to me. Stating the the tableview row height in the viewDidLoad (ie. self.tableView.rowHeight = 350) fixed it.
I solved extra bottom space this way (in viewDidLoad):
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 200 // should be more than real row height will be
It seems like you are observing UIKeyboardWillShowNotification & UIKeyboardWillHideNotification and changing the contentInset of the tableView (adding keyBoard size height to contentInsets) and not setting the contentInsets to UIEdgeInsetsZerowhen keyboard hides.

How do I hide a tableView searchBar

I want to have a searchBar in the tableView that is hidden by default, but if the user pulls down it appears.
So I have used the following code to implement this but when the view is first displayed the searchBar is momentarily visible and I would like avoid this brief flash. Adding self.tableView.contentOffset = CGPointMake(0, 0) to the viewDidLoad() method does not have any affect. Note that the tableView is behind a navigation controller which is why setting the Y offset to 0 effectively hides the searchBar behind the navigation bar. Any idea how to make sure the tableView's headerView is hidden when the view is first be displayed.
I have considered simply removing the headerView but then the user can't drag down to access it.
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
searchBar.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 44)
if let tv = self.tableView {
if let headerView = tv.tableHeaderView {
headerView.addSubview(searchBar)
} else {
FLOG("No table header view is available so create one!")
let headerView = UIView()
let width: CGFloat = tv.frame.size.width
headerView.frame = CGRectMake(0, 0, width, 44);
tv.tableHeaderView = headerView
tv.tableHeaderView!.addSubview(searchBar)
}
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
dispatch_after(0, dispatch_get_main_queue()) {
self.tableView.contentOffset = CGPointMake(0, 0)
}
}
I think there's an ordering issue with viewWillAppear and viewDidLoad. As I understand, viewWillAppear gets called every time a view will be drawn and added to the view hierarchy, whereas viewDidLoad gets called when a VC loads its subview for the first time.
So, I suppose on your first run the view loads via the mainQueue with viewDidLoad which places your search bar at (0,44), then viewWillAppear gets called but actually causes a brief visual blip due to the call to move the table's offset on the mainQueue. But on subsequent calls, since viewDidLoad has already happened, only viewWillAppear gets called. And since the search bar doesn't first start at (0,44) and then needs to move to (0,0), there's no blip.
Rather than directly defining the frame for the search bar, try calling sizeToFit on it after adding it to the tableHeader. Secondly, I don't believe you have to instantiate the header view, just set it equal to the searchbar. Lastly, take the contentOffset call out of the dispatch_queue, it should be handled correctly by viewWillAppear as is.
I went deep into UISearchController for iOS8 recently, and documented the journey (in part at least). For the code I used, here's a link to the implementation file and the corresponding write-up I did. It's in ObjC, so you'll need to do a little translation. But it looks like:
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.filteredResultsTableViewController];
self.searchBar = self.searchController.searchBar;
// other code ...
[self.searchBar sizeToFit];
// other code ...
self.tableView.tableHeaderView = self.searchBar;

Resources