Search Bar Doesn't Appear When View loads - iOS - swift

I'm having a problem when one of my views initiated. I'm trying to get the search bar to show up when the view is initiated, but it shows up when I start scrolling down.
This shows up when I click on it:
and I'm trying to get this to show up when the view is initiated, which currently only shows up only when I start scrolling:
This is the code I have to set the search controller up so far:
searchController.searchBar.scopeButtonTitles = ["Posts", "Users"]
searchController.searchBar.delegate = self
navigationController?.navigationItem.searchController = searchController
navigationController?.navigationItem.searchController?.searchBar.isHidden = false
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search"
searchController.searchBar.isHidden = false
searchController.searchBar.showsScopeBar = true
// searchController.hidesNavigationBarDuringPresentation = false
self.navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.searchController = searchController
// navigationController?.navigationItem.hidesSearchBarWhenScrolling = false
definesPresentationContext = true
I've tried lots of different ways to get the search bar to appear when clicked on but I haven't been successful. Any ideas?

You need to add this line:
navigationItem.hidesSearchBarWhenScrolling = false
And if you wan't to show if from the beginning and hide it when scrolling then you need to do this:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = false
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = true
}
}

Related

UISearchBar height gets overridden by _UITemporaryLayoutHeight - how do apps make search bars the same height as iOS 11?

I constantly see, on snapchat, instagram, and pretty much every major app - UISearchBars which have a height of 44px. However, I have tried every online 'solution' and have not been able to figure this out.
Here is another thread which no one seemed to find a solution to the 'sub-issue' of it - how to make a UISearchBar's height 44px in iOS 12 and up:
UISearchBar increases navigation bar height in iOS 11
Note - I have joined this community on a new account and have been building iOS applications for many years. I am asking if anyone found a solution to this or do you have to build your own custom search bar (UIView with a textfield in it, etc.)?
private var searchController = UISearchController(searchResultsController: nil)
private func setupSearchController() {
navigationItem.searchController = searchController
searchController.delegate = self
searchController.searchResultsUpdater = self
searchController.definesPresentationContext = true
searchController.searchBar.autocorrectionType = .yes
searchController.searchBar.searchBarStyle = .minimal
searchController.obscuresBackgroundDuringPresentation = false
}
override func viewDidLoad() {
super.viewDidLoad()
setupSearchController()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
view.setNeedsLayout()
navigationItem.largeTitleDisplayMode = .never
navigationItem.hidesSearchBarWhenScrolling = true
navigationController?.setNavigationBarHidden(false, animated: false)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationItem.hidesSearchBarWhenScrolling = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationItem.largeTitleDisplayMode = .never
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
navigationItem.hidesSearchBarWhenScrolling = false
}

How to redraw NavigationBar to show SearchController on button press?

I am using a button in my navigationItem.title, which when pressed, I would like to display the navigationItem.searchController.
When cancel is pressed on the search bar, I would like to dismiss the search controller, and redraw the navigation bar.
var universalSearchController = UISearchController(searchResultsController: nil)
override func viewWillAppear(_ animated: Bool) {
// Set search delegate and who will be updating the results
universalSearchController.searchBar.delegate = self
universalSearchController.searchResultsUpdater = self
universalSearchController.delegate = self
definesPresentationContext = true
titleButton.addTarget(self, action: #selector(titleButtonTapped), for: .touchUpInside)
}
Basically everything I have tried is all in here:
#objc func titleButtonTapped() {
// Set the searchController
navigationItem.searchController = universalSearchController
// Below are attempts at redrawing the navigation bar
universalSearchController.searchBar.becomeFirstResponder()
universalSearchController.searchBar.isHidden = false
// Try to refresh by showing/hiding
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.isNavigationBarHidden = false
universalSearchController.view.setNeedsLayout()
universalSearchController.view.layoutIfNeeded()
universalSearchController.view.setNeedsDisplay()
universalSearchController.view.reloadInputViews()
view.setNeedsDisplay()
view.setNeedsLayout()
view.layoutIfNeeded()
view.reloadInputViews()
navigationController!.navigationBar.setNeedsDisplay()
navigationController!.navigationBar.setNeedsLayout()
navigationController!.navigationBar.layoutIfNeeded()
navigationController!.navigationBar.reloadInputViews()
navigationController!.view.setNeedsDisplay()
navigationController!.view.setNeedsLayout()
navigationController!.view.layoutIfNeeded()
navigationController!.view.reloadInputViews()
}
For hiding the searchController:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
// Get rid of the searchController
navigationItem.searchController = nil
universalSearchController.searchBar.isHidden = true
universalSearchController.searchBar.resignFirstResponder()
// Try to refresh by showing/hiding
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.isNavigationBarHidden = false
navigationController?.navigationBar.backgroundColor = .red
universalSearchController.view.setNeedsLayout()
universalSearchController.view.layoutIfNeeded()
universalSearchController.view.setNeedsDisplay()
universalSearchController.view.reloadInputViews()
view.setNeedsDisplay()
view.setNeedsLayout()
view.layoutIfNeeded()
view.reloadInputViews()
navigationController!.navigationBar.setNeedsDisplay()
navigationController!.navigationBar.setNeedsLayout()
navigationController!.navigationBar.layoutIfNeeded()
navigationController!.navigationBar.reloadInputViews()
}
The weird thing is that if I present a view over my current table view, and then dismiss it, the navigation bar is there.

UISeachController Delegate methods not called, searchbar can't become first responder

I'm having some difficulty getting the searchbar in my searchcontroller to become firstResponder. I've noticed the delegate methods are not being called, but the searchbar works as intended when I'm typing to filter a list of users.
Definition of searchcontroller:
lazy var searchController: UISearchController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search"
return searchController
}()
Setting it up:
private func setupSearchController() {
self.navigationItem.searchController = searchController
searchController.definesPresentationContext = true
searchController.delegate = self
searchController.isActive = true
searchController.searchBar.delegate = self
searchController.searchBar.becomeFirstResponder()
}
I tried this suggestion from another SO question but the delegate method isn't being called:
func didPresentSearchController(searchController: UISearchController) {
UIView.animate(withDuration: 0.1, animations: { () -> Void in }) { (completed) -> Void in
searchController.searchBar.becomeFirstResponder()
}
}
The problem is you are trying to access UI element(searchbarcontroller) before UI is completely loaded.
This can be done in 2 ways
Use main queue to show keypad
private func setupSearchController() {
self.navigationItem.searchController = searchController
searchController.definesPresentationContext = true
searchController.delegate = self
searchController.isActive = true
searchController.searchBar.delegate = self
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
With this approach keypad will be only show at one time in viewDidLoad
Show keypad in viewDidAppear
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
With this approach keypad will be always shown whenever screen appears.

UISearchController - Black Rectangle

I'm implementing a simple tableViewController with UISearchcontroller.
The problem is that every time that I press the search field then a black rectangle appear right after the keyboard shows up.
I also tried to use definesPresentationContext and searchBarStyle but it keep showing the rectangle. On the other hand, it looks like doesn't happen in the simulator since there is no keyboard.
Update: Below some photos.
ViewController:
class ListGlobalViewController: UITableViewController, StoryboardSceneBased, ViewModelBased {
static var sceneStoryboard: UIStoryboard = UIStoryboard(name: "DataSelectorViewController", bundle: Bundle.main)
// --------------------
// MARK: - Properties
// --------------------
var viewModel: ListGlobalViewModel!
private let disposeBag = DisposeBag()
private let searchController: UISearchController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.searchBarStyle = .minimal
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = true
return searchController
}()
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
configure(with: viewModel)
navigationItem.largeTitleDisplayMode = .automatic
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.searchController.isActive = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
// --------------------
// MARK: - Functions
// --------------------
func configure(with viewModel: ListGlobalViewModel) {
self.tableView.delegate = nil
self.tableView.dataSource = nil
viewModel.outputs.listDataObservable.bind(to: self.tableView.rx.items(cellIdentifier: "listGlobalCell", cellType: ListGlobalCell.self)) { (index, model, cell) in
cell.model = model
}.disposed(by: disposeBag)
searchController.searchBar.rx.text.filterNil().throttle(1, scheduler: MainScheduler.instance).distinctUntilChanged().subscribe(viewModel.inputs.searchBarObservable).disposed(by: disposeBag)
}
}
Navigation Default Values:
let controller = UINavigationController()
controller.navigationBar.isTranslucent = false
controller.navigationBar.prefersLargeTitles = true
controller.definesPresentationContext = true
controller.navigationBar.titleTextAttributes = [ NSAttributedString.Key.font: UIFont.bold(size: 24), NSAttributedString.Key.foregroundColor: UIColor.black ]
if #available(iOS 11, *) {
controller.navigationBar.largeTitleTextAttributes = [ NSAttributedString.Key.font: UIFont.bold(size: 33), NSAttributedString.Key.foregroundColor: UIColor.black ]
}
return controller
Pictures:
Bugged
Use UITextField instead if UISearchBar. You can give any design to uitextfield. UISearch bar has limited designable attributes. Also you can reach any search function with textfield.

disable hiding searchBar when scrolling

I am coding to setup search bar (not from storyboard)
here are my codes that related to searchbar:
var searchController = UISearchController(searchResultsController: nil)
func setupNavBar() {
self.navigationItem.title = "Tools"
self.navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.hidesSearchBarWhenScrolling = false
}
func configureSearchController() {
filteredData = toolsList.allTools
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.searchBarStyle = .minimal
searchController.searchBar.tintColor = .purple
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.placeholder = "Search for tools"
}
override func viewDidLoad() {
super.viewDidLoad()
setupNavBar()
tableViewConfigurations()
configureSearchController()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
isSearching = true
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
isSearching = false
tableView.reloadData()
}
although with this line of code i ask to disable hiding search bar when scrolling, it is still hiding.
navigationItem.hidesSearchBarWhenScrolling = false
May i ask you to guide me to how i can disable it?
Thank you very much
Looking at Apple's docs I found this:
You must configure the searchController property for this property
[hidesSearchBarWhenScrolling] to have any effect. The navigation
controller hides and shows only the search bar provided by the search
controller in that property.
I'd try adding searchController to navigationItem.
#very_supercharged thanks 😊 i have transferred searchBar from table view to navigationBar
i have changed:
tableView.tableHeaderView = searchController.searchBar
to
navigationItem.searchController = searchController
And now, searchBar does not hide when scrolling.