Search controller below navigation item prior to iOS 11 - swift

I am using this code with no problem, but I would like to place the search controller below the navigation item’s titleView, instead of replacing it. With iOS11 it’s as easy as setting navigationItem.searchController to the searchController, and it will place it below the titleView, but in the navigationItem.
Any ideas on how to do this prior to iOS 11, instead of replacing the titleView?
Current Code:
if #available(iOS 11, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
} else {
navigationItem.titleView = searchController.searchBar
}

I don't know if it's still relevant for you, but for anyone searching an answer and ending up here, this is a way to do it:
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
} else {
tableView.tableHeaderView = searchController.searchBar
}

#holger's answer helps me fix my problem in iOS 10 - which it accidentally hide the whole navigation bar when pressing CANCEL.
Since my app has a logo sitting at the title of navigation bar, the search bar has to be hidden when not in use. So I added a search button as rightBarButtonItem, and trigger #holger's code when pressed.
#IBAction func onSearchAction(_ sender: UIBarButtonItem) {
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
} else {
// Fallback on earlier versions
searchController.hidesNavigationBarDuringPresentation = false
tableView.tableHeaderView = searchController.searchBar
}
searchController.isActive = true
}
func didPresentSearchController(_ searchController: UISearchController) {
asyncAfter(.milliseconds(300)) {
searchController.searchBar.becomeFirstResponder()
}
}
By referring to another answer here, I added becomeFirstResponder() inside didPresentSearchController with a slight delay. So the keyboard will appears without tapping. Finally, implements UISearchControllerDelegate so that it will disappears when cancelled:
func willDismissSearchController(_ searchController: UISearchController) {
if #available(iOS 11.0, *) {
navigationItem.searchController = nil
} else {
// Fallback on earlier versions
tableView.tableHeaderView = nil
}
}

Related

UISearchController setActive does nothing

I'm trying to present a search controller in response to a button, by setting its isActive property, but it doesn't appear.
lazy var searchController: UISeachController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.delegate = self
return searchController
}()
override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
}
// Called when a button on the navbar is tapped
#obcj private func searchTapped() {
// The doc says you can force the search controller to appear by setting isActive,
// but nothing happens
searchController.isActive = true
// Calling present does show it, but the search bar appears behind the navbar.
// And the delegate methods are still not called
//present(searchController, animated: true)
}
func willPresentSearchController(_ searchController: UISearchController) {
// Not called, even when calling 'present'
}
It seems isActive only works if the search bar is in the view hierarchy.
// This will place the search bar in the title view, allowing you to
// have other buttons on the right of the search bar.
navigationItem.titleView = searchController.searchBar
Or
// This takes up a whole other row under title row.
navigationItem.searchController = searchController
But if you go this route, you don't need to set isActive yourself - the search controller automatically comes up when the user interacts with the search bar. I still don't understand how isActive is supposed to be used, but it does answer the original question.

Need to show navigation title while using searchBar in navigationBar

I need to show large navigation title while search with searchBar, but when I'm clicking on Searchbar or starting to type my NavigationTitle is replaced with SearchBar. I checked methods for navigationItem and didn't find any suitable.
Does anybody know how can we always show title, even while searching?
Here is my code
class FavouriteVC: UIViewController {
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Favourite"
navigationItem.searchController = searchController
navigationItem.largeTitleDisplayMode = .always
}
}
And here are shots
screen with NavTitle
screen without NavTitle
Seems like UISearchController has a hidesNavigationBarDuringPresentation that prevents the navigation bar from hiding when set to false
Include:
searchController.hidesNavigationBarDuringPresentation = false
in your viewDidLoad and if I've understood your issue right, this should do what you need.

Scope buttons hide under search bar on iOS 11

I have a search controller in my app which according to apple documentation on iOS 11 has to be added to the navigationItem's searchController property. I also have some scope buttons for the searchController. Everything works fine but when I rotate my device to landscape and rotate back to portrait then a wired thing happens. The scope buttons gets hidden under the search field. If I press the cancel button and tap on the search field again then it comes back to the normal state. The bug reproduces everytime only on iOS 11. The searchbar will look like this:
The normal state of the search controller:
This is how I add the searchController:
searchController.searchResultsUpdater = self as UISearchResultsUpdating
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.tintColor = UIColor.black
searchController.searchBar.sizeToFit()
searchController.searchBar.placeholder = "Search device"
searchController.searchBar.scopeButtonTitles = ["Device", "Person", "OS version", "Serial"]
if #available(iOS 11.0, *) {
self.navigationItem.searchController = self.searchController
self.navigationItem.hidesSearchBarWhenScrolling = false
if let textField = searchController.searchBar.value(forKey: "searchField") as? UITextField {
if let backgroundView = textField.subviews.first {
backgroundView.backgroundColor = UIColor.white
backgroundView.layer.cornerRadius = 10
backgroundView.clipsToBounds = true
}
}
} else {
tableView.tableHeaderView = searchController.searchBar
}
searchController.searchBar.delegate = self as UISearchBarDelegate

UISearchBar alignment issues in iOS 11

I have UITableViewController where i was adding UISearchController searchbar as an headerView and I have changed this to navigationItem.searchcontroller for iOS 11 in iOS 11 searchbar won't appear at all even navigationItem was present.
if don't use this searchbar UI is going for toss. Please suggest me what was i am doing wrong here.
let searchController = UISearchController(searchResultsController: vc)
searchController.searchBar.scopeButtonTitles = ["All", "images", "videos", "others"]
searchController.dimsBackgroundDuringPresentation = false
// Don't remove these two lines then search bar alignment issue will raise
self.extendedLayoutIncludesOpaqueBars = true
self.searchController.searchBar.isHidden = false
definesPresentationContext = false
if #available(iOS 11.0, *) {
self.navigationItem.searchController = searchController // not working for me.
searchController?.hidesNavigationBarDuringPresentation = false
navigationItem.hidesSearchBarWhenScrolling = false
} else {
searchController?.hidesNavigationBarDuringPresentation = true
searchController?.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
}
List of issues are
on iOS 11 with UI goes wrong as attached image if add UISearchbar to header view
if I try add to navigation item as mentioned in the code it is not appearing
As i am using different search results controller when search is active i need to disable actions in present controller - how can i achieve this easily.
I'm not really sure what went wrong there but in my case, it's working fine. Here is my code:
Created a searchController file:
private let searchController = UISearchController(searchResultsController: nil)
In viewDidLoad():
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = kSearchPlaceholder
searchController.searchBar.scopeButtonTitles = [kCategory, kAuthor, kPicture]
searchController.searchBar.delegate = self
definesPresentationContext = true
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
} else {
tableView.tableHeaderView = searchController.searchBar
}
And it's good to go.

After updating to iOS11 my searchBar behaves strange

After updating to iOS11 my searchBar behaves very strange. When activated, it jumps to the top of screen. It works as it should, as before but of course I want it to stay in place. I have tried a lot of solutions from googling this behavior but nothing helps. Do anyone have the same problem? And what did you do to solve this?
searchBar in place
searchBar jumped to top
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
// Setup the Search Controller
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.preservesSuperviewLayoutMargins = true
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
walkaboutTableView.tableHeaderView = searchController.searchBar
searchController.searchBar.barTintColor = matildaLightBlue
searchController.searchBar.clipsToBounds = true
searchController.searchBar.layer.borderWidth = 2
searchController.searchBar.layer.borderColor = UIColor.black.cgColor
}
Adding search controller instance into navigation item instead of table header view helps me to solve similar issue in my project.
if #available(iOS 11, *) {
navigationItem.searchController = searchController
} else {
tableView.tableHeaderView = searchController.searchBar
}
navigationItem.searchController
navigationItem.hidesSearchBarWhenScrolling
Ruslan Kolosovskyi's answer is really good. In addition if you want the search bar to be more accessible:
if #available(iOS 11, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
} else {
tableView.tableHeaderView = searchController.searchBar
}