I currently have an app with a search icon / button at the top in the navigation bar.
I'm not sure if it would be possible with storyboard but i would like to display a search controller that appears with a custom table view and a close button, a lot like the wikipedia app
see examples below
http://i.imgur.com/ggsTj6W.png
http://i.imgur.com/BVDLU2O.jpg
So workflow would be:
- Press the search icon,
- Table view comes up with search focused with a close button
- Search results come in the table view as custom cells from a re-usable source
When I use this search on the wikipedia app it feels very native to ios so I assume there is a way to do it?
thank you
Create a UITableViewController object and conform it to protocol UISearchResultsUpdating
Add the search controller to class
let searchController = UISearchController(searchResultsController: nil)
Add the following code to viewdidload method
self.definesPresentationContext = true
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = true
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = searchController.searchBar
Implement the following method to conform to UISearchResultsUpdating protocol
func updateSearchResultsForSearchController(searchController: UISearchController)
On the main page (where you want to show the search button), create a segue to the above tableViewController and set it to present modally when button is tapped.
Related
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.
Having an issue with adding a search controller to a navigationItem in iOS11 / Swift 4.
Basically everything works as expected for the most part, pull down will reveal the search bar and searching works fine. However when trying to hide the search bar by scroll back up... the bar won't hide completely and remains as a thin strip (see below).
I have declared my search controller as follows:
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.scopeButtonTitles = ["All", "Samples"]
searchController.searchBar.delegate = self
navigationItem.searchController = searchController
Before (scroll down to reveal search bar):
After (scroll up to hide):
As discussed in this Apple forums thread.
When the value of this hidesSearchBarWhenScrolling is true, the search bar is visible only when the scroll position equals the top of your content view, that's in case you are using a UIViewController, which view property is a normal UIView (It is not a subclass of UIScrollView).
Instead, try to use UITableViewController or ScrollView, it should work as expected
In my case it was happening only when there was a small num of items in the table.
I came to a non-technical, but rather a logical solution to show the search bar only when there are >10 items in the list. There is no need to have search when you have only a few items anyway.
Try to add this
self.navigationItem.hidesSearchBarWhenScrolling = true
I am adding UISearchController searchBar to the controllers' view like this: self.view.addSubview(searchController.searchBar). The functionality is working perfectly fine except that upon selection of the tableview row the searchbar quickly moves down and reappears from the top. I tried the following things, none of which worked out:
Setting tableView.tableHeaderView = searchController.searchBar instead of directly adding to the view
Adding searchController.searchBar to a separate view that I dragged to the controller setting up constraints on it. Tried clipping to bounds both the newly created view and the searchBar.
Embedding the controller in UINavigationViewController and setting self.navigationItem.titleView = searchController.searchBar. I defined the frame of the searchBar, still nothing.
Tried playing with Extend Edges feature in the storyboard (Under top bars, etc.), but no selection worked out
Adding lines (to viewDIdLoad):
self.extendedLayoutIncludesOpaqueBars = true
self.definesPresentationContext = true
Any help would be greatly appreciated.
If you are using storyboards, you can change it by selecting the view controller and in the attributes inspector deselect Adjust scroll view insets.
After trying all of the suggestion and searching over the internet, it caught my eye that the working examples of the UISearchController implementation are done in UITableViewController, but I had UIViewController with UITableViewDataSource and UITableViewDelegate protocols on it. Unfortunately, due to app architecture I was not able to directly have UITableViewController, so I needed to restructure the app, so that it had UINavigationController where I embeded the searchBar in navigationItem.titleView (and not set it as tableView.tableHeaderView like they always do in various tutorials since I needed the searchBar to be fixed, not hidden when we do scrolling) and it worked. Here is how the ultimate working app architecture looks like:
The TrainingContainerViewController has two Container Views, in one we embed TrainingFilterTableViewController that shows up the ultimate results of the autocomplete functionality (after clicking on an autocomplete row). Another Container View embeds UINavigationController (to the left) which, in turn, has TrainingSearchTableViewController as its child.
The code that sets up the UISearchController and its searchBar is located in the TrainingSearchTableViewControllers' viewDidLoad and is the following:
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
searchController.delegate = self
navigationItem.titleView = searchController.searchBar
tableView.hidden = true
...
}
Nothing else was needed to fix the bug in XCode 8.2.1 and Swift 2.3, just change architecture, so that usage of UITableViewController is possible in the app and use it instead of UIViewController.
I need to have a UISearchBar above a UITableView (ie. the search bar is not part of the table view), and what I found is that when the search bar is activated, it moves off screen.
I did a fair bit of search and could not find a solution, there are ‘search bar off screen’ issues but they are adding search bar to table's header view and tweaking properties like definesPresentationContext fixed it.
My view hierarchy:
VC’s view
|— top view
|— segmented control
|— search bar
|— table view
Looks like UISearchController expects the search bar to be inside the table view, and always shifts the table view so that the search bar moves to the very top of screen.
Anyone having the same issue and found a solution?
Thanks a lot!
// Swift 5
// if you are using UISearch Controller then simply add line below to your
viewDidLoad() and it will fix the issue.
override func viewDidLoad() {
super.viewDidLoad()
// fixes the search moving to next screen when its active
self.definesPresentationContext = true
}
Updates
After further testing I decided to just implement the UISearchBar delegate and stop using the UISearchController since I was just reusing my UICollectionView for the results. Found a great guide on how three different methods to implement the SearchBar.
Edge Case #1
TLDR
Enable clips to bounds on the containing view. Or if you have a collection view cell that has a user-generated content view, enable clips to bounds on that content view.
Details:
An additional very important fact is that you may have the search bar embedded in a container view. This can cause issues if the container view does not have clips to bounds enabled. Other examples of this being a problem is the user-generated content views in UICollectionViewCells. Compare the setting on a UITableViewCell auto-generated content view to observe the difference.
Summary
A Boolean value that determines whether subviews are confined to the
bounds of the view. Declaration
var clipsToBounds: Bool { get set } Discussion
Setting this value to true causes subviews to be clipped to the bounds
of the receiver. If set to false, subviews whose frames extend beyond
the visible bounds of the receiver are not clipped. The default value
is false.
Swift 4.x Solution
In my case, this was happening both inside a UICollectionView and inside of a UIStackView. I was able to keep my searchBar in place after noticing the following info in the searchBar quick help.
Summary
The search bar to install in your interface. Declaration
var searchBar: UISearchBar { get } Discussion
Before presenting your searchable content, install the search bar in
this property somewhere into your view controller’s interface. The
search bar becomes the starting point for searching your contents.
Interactions with the search bar are handled automatically by the
UISearchController object, which notifies the object in the
searchResultsUpdater property whenever the search information changes.
To use a custom subclass of UISearchBar, subclass UISearchController
and implement this property to return your custom search bar.
After that I was able to resolve the issue successfully by doing the following:
let searchController = UISearchController(searchResultsController: nil)
var searchBar:UISearchBar!
Sometime later I assign the searchBar from the searchController to the searchBar in my UIViewController...
BTW - I embed my searchBar in a container UIView that has all the contraints I need to keep it in place.
func setupSearchController<T:UIViewController>(delegate vc:T) where T: UISearchResultsUpdating, T:UISearchBarDelegate {
searchBar = searchController.searchBar //this is the key
searchController.searchResultsUpdater = vc
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search".localized()
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.delegate = vc
searchController.searchBar.showsCancelButton = true
definesPresentationContext = true
self.searchMenu.addSubview(searchBar)
//searchMenu is a constrained UIView in my hierarchy
}
I believe putting searchBar inside tableView is not mandatory. I had same issue some time back. All you need to do is setting proper auto layout constraint. Adjust leading and trailing of searchView as align to leading and trailing of the tableView. Also release the margin property from constraints. Hope this may help you.
After a few tries, I've found the reason being that when the UISearchBar is activated, UISearchController removes it from your view and puts it on its own view with a table view for showing the results, since I use auto-layout for the search bar, by removing it, some of the constraints are screwed up. So my solution was to not use auto layout for the UISearchBar from UISearchController.
If you choose to use UISearchBar without an UISearchController, which I have found much easier for keeping UISearchBar within its initial bounds, here is the code template:
final class MyUIViewController: UIViewController {
// MARK: Properties
private let tableView = UITableView()
private let searchBar = UISearchBar()
...
// MARK: View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
...
searchBar.delegate = self
searchBar.sizeToFit()
tableView.tableHeaderView = searchBar
}
}
extension MyUIVewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
... // Your code filtering tableView dataSource goes here
tableView.reloadData()
}
}
I want to make my search bar stop scrolling along with table view. I tried to add search controller into viewForHeaderInSection and it failed.Also I want to try to show original content while search bar active. So I try to do it in viewDidLoad but I don't know how to make it work. Here is my code for both of method.
searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.Prominent
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
Do you have any suggestion?
Add both the table view and the search view into another view (which becomes the view of your view controller). Then the search view will be completely disconnected from your table view.
Note that if your view controller is currently a table view controller subclass you will need to change that to be a simple view controller subclass.
You are adding the searchbar to the header view. If you want to keep it above your table you can add it to the navigation controller view. How do I use UISearchController in iOS 8 where the UISearchBar is in my navigation bar and has scope buttons?