How can I mimic safari's search bar UI/animations in Swift? - ios

I am attempting to mimic the search bar behavior below in iOS Safari on my current app:
I mainly want the navigation bar to scroll up to a very small version when the user scrolls on the content and comes back when they scroll back up.
I've tried using scrollViewDidScroll but I cannot seem to get it to mimic that behavior. I'm unsure if I am adding the search bar correctly to the navigation bar.
let searchBar: UISearchBar = {
let sb = UISearchBar()
sb.autocapitalizationType = .none
sb.autocorrectionType = .no
sb.keyboardAppearance = UIKeyboardAppearance.default
sb.placeholder = "Search"
return sb
}()
fileprivate func setupNav() {
//Basic Setup
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
//Search Bar
searchBar.sizeToFit()
navigationItem.titleView = searchBar
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//Implement
}

let searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search"
searchController.searchResultsUpdater = self
navigationItem.searchController = searchController
definesPresentationContext = true
Put your SearchController in the Navigation Item instead. This will add collapsable SearchBar. Additionally you can try with Navigation Item Prompt for very small title on top.

Related

UISearchController appears behind NavigationBar

I'm trying to show the UISearchController by tapping on the UIBarButtonItem. But the SearchBar appears behind the NavigationBar. If I set definesPresentationContext = false, then the SearchBar appears above the NavigationBar, but the transitions don't work.
#IBAction func searchButtonPressed(_ sender: Any) {
searchResultsController = self.storyboard?.instantiateViewController(withIdentifier: "SearchResultsController") as? SearchResultsController
searchResultsController.tableView.delegate = self
let searchController = UISearchController(searchResultsController: searchResultsController)
searchController.searchResultsUpdater = searchResultsController
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.autocapitalizationType = .words
definesPresentationContext = true
present(searchController, animated: true)
}
Before BarButtonItem tapped
After BarButtonItem tapped
View UI Hierarchy
Interface Builder
searchController.hidesNavigationBarDuringPresentation = false solve this problem, but I need the navigation bar to not be hidden
UPDATE:
Inserting the SearchBar inside the Navigation Bar is not suitable for my app
https://imgur.com/a/74e5sSk
If you are using UITableViewController then you can do the following:
let searchController = UISearchController(searchResultsController: nil)
searchController.obscuresBackgroundDuringPresentation = false
searchController.definesPresentationContext = true
Then, you need to assign this searchController to navigationItem:
self.navigationItem.searchController = searchController
Now searchbar is going to appear when you pull the tableview and will look this way:
If you want to keep the search bar permanently, then do this:
self.navigationItem.hidesSearchBarWhenScrolling = false

I'm using UISearchController, and while using it, search bar moves up/down when I click "cancel" button. Why does it happen?

I have TableViewController: UITableViewController.
I have implemented
let searchController = UISearchController(searchResultsController: nil).
I use SearchBar as tableView.tableHeaderView
While I'm using search, SearchBar moves up/down when I click cancel button. Why does it happen?
searchController.searchBar.delegate = self
definesPresentationContext = true
searchController.dimsBackgroundDuringPresentation = false
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.returnKeyType = .done
searchController.searchBar.enablesReturnKeyAutomatically = false
check it

How do I display a UISearchController on a UINavigationItem without an underlying UIScrollView?

Maybe this is impossible, but I always assumed you could just throw a UISearchController instance onto any old view controller's navigationItem and get a search bar. It seems to me like no matter what I try, I can't get it to work. It's making me think this behavior is hardcoded to only work when the view controller's view property is a subclass of UIScrollView.
I hope this is just a red herring. If I missed something obvious, please help! This is infuriating.
Here's what I did:
import UIKit.UIViewController
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesSearchBarWhenScrolling = false
navigationItem.searchController = {
let searchController = UISearchController()
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
return searchController
}()
}
}
No search bar ever appears on screen. It just looks like a regular old navigation bar.
The UISearchController initializer should be let searchController = UISearchController(searchResultsController: nil) or replace nil with a seperate controller to display the search results.
If your viewController is in a UINavigationController stack then the above code should work (with the corrected initializer). Otherwise you will need to create a UINavigationBar and add it to the view. Then add the searchController.searchBar to the navigationItem.titleView
let navigationBar = UINavigationBar()
view.addSubview(navigationBar)
navigationBar.barTintColor = UIColor.gray
navigationBar.translatesAutoresizingMaskIntoConstraints = false
navigationBar.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
navigationBar.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
navigationBar.delegate = self
navigationBar.items = [navigationItem]
navigationItem.searchController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
return searchController
}()
navigationItem.titleView = navigationItem.searchController?.searchBar

How to navigate to another view controller when search bar is clicked

I am a bit stuck here. I have a search bar embedded in my navigation bar as the title which I want.
However next I would like to navigate to another view controller containing a UIsearchcontroller in a collection view, and when cancel is tapped the user is brought back to the previous view. (Very similar to Facebook or Instagrams use of the search bar controller)
Is there anyway I can use the search bar as a button to navigate to the next view controller that handles all of the search functions?
This is what I have so far for the search bar.
func setUpNavBar() {
let searchBar = UISearchBar()
searchBar.sizeToFit()
searchBar.searchBarStyle = .minimal
searchBar.placeholder = "Search by username"
searchBar.tintColor = UIColor.lightGray
searchBar.barTintColor = UIColor.lightGray
navigationItem.titleView = searchBar
searchBar.isTranslucent = true
}
Edit
Just to add on to the answer below, if anyone comes across this and you want to get the effect that treats the search bar as a button use
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
self.present(UINavigationController(rootViewController: SearchBarController()), animated: true, completion: nil)
searchBar.setShowsCancelButton(false, animated: true)
return false
}
This way, when you click the search bar, you do not get the effect that shows the search bar active,( if that makes sense). When you tap the search bar, there is no effect, it just takes you to the (real) search view controller then the search bar is active and the keyboard is displayed with a cancel button. I hope that makes sense, if anyone wants an example go to Instagram, FB, or Pinterest and tap on their search bar or search icon and you'll see.
Add UISearchBarDelegate in first view controller. And in searchBarTextDidBeginEditing method present the second view controller.
//ViewController.swift
class ViewController: UIViewController, UISearchBarDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setUpNavBar()
}
func setUpNavBar() {
let searchBar = UISearchBar()
searchBar.delegate = self
searchBar.sizeToFit()
searchBar.searchBarStyle = .minimal
searchBar.placeholder = "Search by username"
searchBar.tintColor = UIColor.lightGray
searchBar.barTintColor = UIColor.lightGray
navigationItem.titleView = searchBar
searchBar.isTranslucent = true
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.present(UINavigationController(rootViewController: SearchViewController()), animated: false, completion: nil)
}
}
//SearchViewController.swift
class SearchViewController: UIViewController {
let searchBar = UISearchBar()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setUpNavBar()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchBar.becomeFirstResponder()
}
func setUpNavBar() {
searchBar.sizeToFit()
searchBar.searchBarStyle = .minimal
searchBar.placeholder = "Search by "
searchBar.tintColor = UIColor.lightGray
searchBar.barTintColor = UIColor.lightGray
navigationItem.titleView = searchBar
searchBar.isTranslucent = true
}
}

Search bar not showing up on the navigation bar iOS 11

I am pushing a viewController where I want a searchBar, but search bar is not showing at all. Below is the code. Am I missing something?
var searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
definesPresentationContext = true
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
if #available(iOS 11.0, *) {
self.navigationItem.searchController = searchController
} else {
// Fallback on earlier versions
navigationItem.titleView = searchController.searchBar
navigationItem.titleView?.layoutSubviews()
}
You need to add this line to your code:
navigationItem.hidesSearchBarWhenScrolling = false
That removes hiding searchBar while scrolling and shows it on pushing your view controller.
So, navigationItem.hidesSearchWhenScrolling only works when you set the searchController property of navigationItem NOT when you set the navigationItem.titleView to searchBar.

Resources