UISearchBar in UINavigationController - ios

I am wondering to programmatically put a UISearchBar into UINavigationController, rather than replacing UINavBar title, as I want the large title to show up. See Files app on iOS.
Here is my .swift
class Search: UITableViewController, UISearchBarDelegate
override func viewDidLoad() {
super.viewDidLoad()
searchBar()
}
func searchBar() {
let searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
navigationItem.searchController?.searchBar.placeholder = "search".localized
navigationItem.searchController?.dimsBackgroundDuringPresentation = false
navigationItem.hidesSearchBarWhenScrolling = false
}
The point is: by changing nil to actual searchResultsController, after typing text into search bar, the whole navigation controller (with search bar and typed text) got replaced by the searchResultsController view. No search bar while typing into it in short.
I am trying hard to use iOS 11/12 native look and feel within the app and putting the search bar into TableViewController is a no way here. Can someone help me?

If you don't need a different view controller to display the results simply use (it will not make your navigation bar disappear):
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
And do not change the value after that.
Most of your code is good, however you will need to implement the UISearchResultsUpdating protocol to detect updates (when the user write in the search bar) and use a table view (inside your view controller) to display the results of the search.
You do that by reloading the data of your table view inside the function: updateSearchResults(for searchController:) after filtering the data you want with the text inside the search bar. You can read this good tutorial on the subject for more information.

Related

Search Bar Animation Override

I am in the middle of implementing search into a tableView based app. I have currently implemented it using a UIView in Storyboard (which I have placed in the tableHeaderView) with the following code:
resultsTableController = SearchResultsTableViewController()
resultsTableController.tableView.delegate = self
searchController = UISearchController(searchResultsController: resultsTableController)
searchController.searchResultsUpdater = self
tableViewSearchBarView.addSubview(searchController.searchBar)
I am currently getting this jerky animation: https://imgur.com/a/7h0J15e
Can I create a custom animation that will happen when the search bar is clicked and cancelled and override this animation somehow? I can't use the normal:
navigationItem.searchController = searchController
as I need to have the Title in a custom tableHeaderView and not in a navigationBar.
How could I go about doing this? I am just wanting a normal animation like what is in the stock Apple Notes App.

UISearchController / UINavigationBar shows broken animation when used within UINavigationController

I have this NavigationController hat has Large Titles enabled for its NavigationBar. The root ViewController has a SearchController, and hidesSearchBarWhenScrolling is set to True in the ViewController's NavigationItem as I don't want the SearchBar to be always visible. The ViewController has a TableView and when you tap on one of its items a new instance of the same ViewController will be pushed onto the Navigation stack using a storyboard segue. However, when looking at the transition between the current and the new ViewController one can observe that the animation doesn't look right: As soon as the new ViewController is moved in the SearchBar becomes empty, just showing its background. When the new ViewController is finally fully visible, the SearchBar will go away without any animation.
This is how I add the SearchController (nothing fancy here):
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = true
}
}
And so it looks like when navigating from "One" to "Two":
UISearchController / UINavigationBar shows broken animation when used within UINavigationController
Is there a way to make this look nicer? Of course, in the new ViewController the SearchBar should not be initially visible, so it has to go away somehow. But I would think that the SearchBar on the old ViewController perhaps should be faded out somehow instead of staying there and then suddenly hiding when the transition to the new ViewController is finished. Hopefully I'm just doing something wrong here...
Thanks and Merry Xmas to all of you,
Peter
Try setting the search controller to nil in the viewWillDissappear method.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationItem.searchController = nil
}
Well, I finally found something very useful that I just couldn't find before asking my question:
Broken UISearchBar animation embedded in NavigationItem
Too bad this is known since iOS 11 and still not fixed.

Exit the editing state after performing a search with Search Controller

I'm using a search controller in order to implement a search section in an iOS app. I'm using iOS 11 and xCode 10.
My scene is a Table View Controller. I have included a search bar programmatically with the following code:
override func viewDidLoad() {
super.viewDidLoad()
let searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.delegate = self
definesPresentationContext = true
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
}
I have also included a UISearchBar delegate extension:
extension SearchTableViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
tableView.reloadData()
episodeResultsArray = []
let searchTerm = searchBar.text!
let escapedSearchTerm = searchTerm.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
performSearch(forTerm: escapedSearchTerm)
}
}
The performSearch function connects to a database via AlamoFire and returns the results which are then listed in the Table View.
When I run the app, the table appears empty (as it should be initially). When I click on the search bar, it enters the editing state (the navigation bar collapses, the search bar sticks to the top, a Cancel button appears, and a translucent grey box covers the rest of the screen.
When I search for something, the results are succesfully listed in the table. However, even though the results are visible, I still remain in the editing state for the search bar. I need to click on the translucent box to exit the editing state and only then I am able to scroll through the results.
How can I exit the editing state after I click on Search so I'm able to scroll through the table as soon as I get the results?
I tried using searchBar.resignFirstResponder() but this only dismisses the keyboard. I also tried
searchBar.endEditing(true)
but even though the search bar loses focus, I'm still in the editing state.
Just to clarify, I need for this to work as a search from scratch, not as a filter, meaning not just showing a subset of results as I type.
Found the answer. The solution is to add
searchController.isActive = false

UISearchController dismisses VC upon hitting cancel button

So, I am currently trying to replace the depricated searchDisplayController in one of my projects with UISearchController and I am running into this problem.
If there are no results in the search (the UITableView is empty) the whole ViewController is dismissed. This does not happen when the search results are not empty. I wan't to make it clear I am not using a UITableViewController. Instead I have a regular VC with a UITableView in it.
Here is some of my code:
var resultSearchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.delegate = self
controller.searchBar.delegate = self
self.studentTable.tableHeaderView = controller.searchBar
return controller
})()
....
}
Now, if I add this function to the equation the cancel button always dismisses the VC.
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
resultSearchController.active = false
}
So why exactly does setting the searchController.active = false dismiss the VC? Is it because it is using the same UITableView as the VC? I believe that the old searchDisplayController would just display a UITableView over the one being used. If this is the case is there a way to override the dismissVC?
this is also Happening to me. The Way I Solve it is by Replacing:
resultSearchController.active = false
with
resultSearchController.searchBar.text = ""
resultSearchController.searchBar.resignFirstResponder()
I Hope this helps you :-)
2018 Just wanna share the fruits of my 1-2 hours debugging.
I had multiple issues with using UISearchController with UITabBarController, namely:
This one, this very question of the OP. Hitting cancel button dismisses the screen that is presenting the searchController.
The tab (or the screen) becomes black, Tab Bar and UISearchController giving black screen
Using UISearchController inside the title view of the navigation bar of UINavigationController in both iOS 10, 11, and 12, like this questions. UISearchBar increases navigation bar height in iOS 11
And for the solution for #3, since we're already here: https://stackoverflow.com/a/53264329/3231194
Finally, the ONLY solution that I have been seeing all this time is adding this code:
self.definesPresentationContext = true
The issue is that I was putting this in a wrong function.
Remember, that solution solved the #1, and #2 problem that I had. Nothing more, nothing less.
Where to add that? Inside the viewDidAppear. That's it!

Use UISearchController without storyboard

I am relatively new to iOS (100 hours or so) and I am trying to implement a UISearchController without a storyboard. Is it possible to do this programmatically?
You have to implement UISearchController programmatically since Apple hasn't provided the ability to set it up using Storyboard yet.
Here are the steps to implement UISearchController in a view controller
Conform to UISearchResultsUpdating Protocol
Create a variable to reference the UISearchController
var searchController: UISearchController!
Set searchController in viewDidLoad(_:)
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
// The object responsible for updating the contents of the search results controller.
searchController.searchResultsUpdater = self
// Determines whether the underlying content is dimmed during a search.
// if we are presenting the display results in the same view, this should be false
searchController.dimsBackgroundDuringPresentation = false
// Make sure the that the search bar is visible within the navigation bar.
searchController.searchBar.sizeToFit()
// Include the search controller's search bar within the table's header view.
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
}
Implement the method updateSearchResultsForSearchController(_:), which is called when the search bar becomes the first responder or when the user makes changes to the text inside the search bar
func updateSearchResultsForSearchController(searchController: UISearchController) {
// No need to update anything if we're being dismissed.
if !searchController.active {
return
}
// you can access the text in the search bar as below
filterString = searchController.searchBar.text
// write some code to filter the data provided to your tableview
}

Resources