How do I hide my Searchbar when scrolling? - ios

My SearchController has unintended behaviour of showing up translucent on top of my scrolling content:
Ideally, I want it to scroll up with my content and the navigation bar to collapse.
Any tips on how to achieve this?
I'm creating my SearchController in ViewDidLoad like so:
let searchResultsController = SearchViewController(nibName: "SearchViewController", bundle: nil)
let searchController = UISearchController(searchResultsController: searchResultsController)
searchController.searchResultsUpdater = searchResultsController
searchController.searchBar.autocapitalizationType = .sentences
searchController.obscuresBackgroundDuringPresentation = true
searchController.searchBar.placeholder = "Search Birds"
searchController.searchBar.delegate = self
navigationItem.searchController = searchController
definesPresentationContext = true
In ViewWillAppear, I set my NavigationController:
self.navigationController!.setNavigationBarHidden(false, animated: true)
I create my Navigation controller in AppDelegate like:
public func applicationDidFinishLaunching(_ application: UIApplication) {
// Instantiate the initial controller
let initialViewController = HomeViewController(nibName: "HomeViewController", bundle: nil)
let navigationController = UINavigationController(rootViewController: initialViewController)

You can try (If you App runs on iOS 11.0 and more)
override func viewDidAppear(_ animated: Bool) {
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = true
}
}
Apple doc:
If this property is true (the default), the searchController’s search
bar will hide as the user scrolls in the top view controller’s scroll
view. If false, the search bar will remain visible and pinned
underneath the navigation bar.

You can try with following:
override func viewWillAppear(_ animated: Bool) {
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = false
}
}
override func viewDidAppear(_ animated: Bool) {
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = true
}
}

navigationItem.hidesSearchBarWhenScrolling = true

Make your controller confirm to UIScrollViewDelegate and override these methods:
extension ViewController: UIScrollViewDelegate{
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.navigationController!.setNavigationBarHidden(true, animated: true)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
self.navigationController!.setNavigationBarHidden(false, animated: true)
}
}
This might require some changes as per the aesthetics you are looking for in the app.

Related

Show search bar without having to scroll up first?

I am trying to add a search bar to my table view so it can filter settings for the user. The only problem is it is initially hidden when the view first loads, giving no indication it is available.
It only shows after you scroll up.
I found a solution that worked back in iOS 11: https://stackoverflow.com/a/46352230/7838349. Unfortunately it seems like this implementation is rather buggy in iOS 13 and seems to no longer work and still seems to show after scrolling.
For reference this is the code I have with the buggy implementation:
class SelectSettingViewController : UITableViewController {
weak var delegate: SelectSettingDelegate?
var settings: [String] = []
var filteredSettings: [String] = []
let searchController = UISearchController(searchResultsController: nil)
var isSearchBarEmpty: Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 1
searchController.searchResultsUpdater = self
// 2
searchController.obscuresBackgroundDuringPresentation = false
// 3
searchController.searchBar.placeholder = "Search settings"
// 4
navigationItem.searchController = searchController
// 5
definesPresentationContext = true
navigationItem.hidesSearchBarWhenScrolling = false
if let indexPath = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: indexPath, animated: true)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationItem.hidesSearchBarWhenScrolling = true
}

Awkward search controller animation on unwind to view with hidden navigation bar

So I'm following this tutorial on UISearchController, and modified it slightly. I created a RedViewController before the SearchViewController, in which the navigation bar is hidden. As you can see in the animation, unwinding from the SearchViewController to the RedViewController isn't kind to the search bar. Additionally, if you don't complete the unwind segue (by swiping back, then forward), the entire search bar disappears. I tried dismissing the search controller on viewWillDisappear, but it didn't work.
Animation
SearchViewController:
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search Candies"
navigationItem.searchController = searchController
definesPresentationContext = true
}
override func viewWillDisappear(_ animated: Bool) {
navigationItem.searchController?.dismiss(animated: false)
}
RedViewController:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setNavigationBarHidden(false, animated: animated)
}

Swift iOS -How to get keyboard to present itself at the same exact time a SearchController is presented?

Just for context my keyboard successfully appears so that's not the problem.
I have a searchButton as my rightBarButtonItem, when pressed it modally presents a vc that contains a SearchController. When the SearchController is presented the keyboard is also presented but the keyboard appears a second late, there's like a 1 second delay before it shows itself. Basically the vc appears on the scene and then the keyboard appears afterwards, I cannot get the keyboard to appear at the same time the SearchController is presented. I was on YouTube's and Vimeo's iOS apps and when I pressed their search button the keyboard is presented with the SearchController at the same exact time, there isn't a 1 second delay.
How can I get the keyboard to present itself at the same time the SearchController is presenting itself?
button to modally present SearchController:
#objc func searchButtonTapped() {
let searchVC = SearchController()
let nav = UINavigationController(rootViewController: searchVC)
present(nav, animated: true, completion: nil)
}
SearchController:
I've already tried adding searchController.isActive = true and searchController.searchBar.becomeFirstResponder() in DispatcQeue.main in viewWillAppear and viewDidAppear and it made no difference
class SearchController: UIViewController {
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.showsCancelButton = true
searchController.searchBar.placeholder = "Search"
searchController.searchBar.returnKeyType = .search
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.sizeToFit()
searchController.searchBar.tintColor = UIColor.black
definesPresentationContext = true
navigationItem.hidesBackButton = true
navigationItem.titleView = searchController.searchBar
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
searchController.isActive = true
}
// I tried both of these searchContrller delegate methods SEPERATELY but it made no difference, there's still a 1 second delay
func presentSearchController(_ searchController: UISearchController) {
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
func didPresentSearchController(_ searchController: UISearchController) {
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
}
Sure there is a delay.. ones this animation is completed, then keyboard appears.
present(nav, animated: true, completion: nil)
Please try this.
It will immediately open the keyboard if you would not preset view controller with an animation but if we present view controller animation it opens keyboard after the present animation is finished.
Thanks.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}

UISearchController in navigation bar could not hide properly on iOS 11

I want to hide navigation bar after a tap
navigationController?.hidesBarsOnTap = true
The navigationBar hides properly after a tap
But after adding a searchController (code below)
let searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
My view (cyan color) could not extend correctly
And I also tried rotated it. The search bar appears.
Finally found a solution
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.barHideOnTapGestureRecognizer.addTarget(self, action: #selector(barHideAction(_:)))
let searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
navigationController?.hidesBarsOnTap = true
}
#objc func barHideAction(_ guesture: UITapGestureRecognizer) {
updateFrame()
}
func updateFrame() {
if let nc = navigationController {
let isHidden = nc.isNavigationBarHidden
searchController.searchBar.superview?.isHidden = isHidden
if isHidden {
self.additionalSafeAreaInsets.top = -64 // fixed by a magic num
}
else {
self.additionalSafeAreaInsets.top = 0
}
}
}
example code

How to show keyboard automatically when searchController is presented

#IBAction func MapSearchController(_ sender: UIBarButtonItem) {
let searchTable = storyboard!.instantiateViewController(withIdentifier: "SearchTableViewController") as! SearchTableViewController
mapSearchController = UISearchController(searchResultsController: searchTable)
mapSearchController.searchResultsUpdater = searchTable
present(mapSearchController!, animated: true, completion: nil)
mapSearchController.searchBar.becomeFirstResponder()
self.mapSearchController.dimsBackgroundDuringPresentation = true
self.mapSearchController.searchBar.sizeToFit()
self.mapSearchController.searchBar.barTintColor = UIColor.black
self.mapSearchController.searchBar.placeholder = "חפש ברים"
self.mapSearchController.hidesNavigationBarDuringPresentation = true
mapSearchController.searchBar.delegate = self
definesPresentationContext = true
searchTable.mapView = mapView
searchTable.handleMapSearchDelegate = self
How to show keyboard automatically when searchController is presented? i tried a lot of solutions but none of them worked for me ..including becomeFirstResponder() and such... please help
Problem is Search controller is not presented when view id loaded so even after making becomeFirstResponder doesn't solve the issue. Below code will fix the issue and open the keyboard with cursor in searchbar.
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
First, move:
present(mapSearchController!, animated: true, completion: nil)
to the end, after you are finished settings all the properties on mapSearchController.
Then make sure you add the delegate method:
func didPresentSearchController(_ searchController: UISearchController) {
searchController.searchBar.becomeFirstResponder = true
}
If that still doesn't work, make sure this VC conforms to the search UISearchControllerDelegate.
You're setting it too early. At that moment the the viewDidLoad of the your MapSearchController instance hasn't been triggered yet. You can only becomeFirstResponder after viewDidLoad.
So what you have to do is: set the becomeFirstResponder in the viewDidAppear of MapSearchController.

Resources