Reputation:
I have implemented the new SearchController
with its searchBar
and the searchResultsController
.
Here is how I implemented it :
The resultViewController:
lazy var resultViewController: SearchResultViewController = {
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let searchResultViewController = storyboard.instantiateViewController(withIdentifier: "SearchResultViewController") as! SearchResultViewController
searchResultViewController.delegate = self
return searchResultViewController
}()
And this is the SearchController:
lazy var searchController: UISearchController = {
let searchController = UISearchController(searchResultsController: resultViewController)
searchController.searchBar.delegate = self
searchController.obscuresBackgroundDuringPresentation = true
searchController.searchResultsUpdater = self
searchController.searchBar.placeholder = "Search.city.label".localizable()
searchController.searchBar.tintColor = UIColor.white
searchController.searchBar.barTintColor = UIColor.white
UITextField.appearance(whenContainedInInstancesOf: [type(of: searchController.searchBar)]).tintColor = UIColor(red:0.00, green:0.47, blue:0.78, alpha:1.0)
if let textfield = searchController.searchBar.value(forKey: "searchField") as? UITextField {
if let backgroundview = textfield.subviews.first {
// Background color
backgroundview.backgroundColor = UIColor.white
// Rounded corner
backgroundview.layer.cornerRadius = 10;
backgroundview.clipsToBounds = true;
}
}
definesPresentationContext = true
return searchController
}()
In my viewWillAppear
I set the navigationItem.searchController :
self.searchController.isActive = true
if #available(iOS 11.0, *) {
self.navigationItem.searchController = searchController
self.navigationItem.hidesSearchBarWhenScrolling = true
} else {
// Fallback on earlier versions
}
I have been able to handle the cancelButtonClicked :
extension HomeViewController: UISearchBarDelegate {
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.endEditing(true)
self.searchController.isActive = false
}
}
This is doing the "cancel" animation, hiding keyboard + inactive state on searchBar/searchController. Both at the same time, with 1 tap on cancel Button.
But I am unable to achieve this when the user tap anywhere on the view.
I tried with tap gesture but it requires me 2 tap to achieve the same behavior.
NB:
I got an UICollectionView in my UIViewController, which takes all the place in the UIView.
Here is what I have tried :
override func viewDidLoad() {
super.viewDidLoad()
handleTapAnywhereToRemoveKeyboard()
}
func handleTapAnywhereToRemoveKeyboard() {
let singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.singleTap(sender:)))
//singleTapGestureRecognizer.numberOfTapsRequired = 1
singleTapGestureRecognizer.cancelsTouchesInView = false
self.view.addGestureRecognizer(singleTapGestureRecognizer)
}
@objc func singleTap(sender: UITapGestureRecognizer) {
self.searchController.isActive = false
self.searchController.searchBar.resignFirstResponder()
self.searchController.searchBar.endEditing(true)
}
EDIT:
I was thinking, maybe it's because my searchBar and searchController aren't in the UIViewController's view hierarchy, but more in the NavigationController one.
So I also tried with :
navigationController?.view.endEditing(true)
I then was thinking, maybe it's because the UIScrollView within my UICollectionView is catching the tap. So I tried to link the tap gesture on the UICollectionView instead of the UIView, but without success.
Upvotes: 1
Views: 1544
Reputation: 720
override func viewDidLoad(){
let tapView = UITapGestureRecognizer(target: self, action: #selector(self.hideKeyboard))
self.view.addGestureRecognizer(tapView)
}
@objc func hideKeyboard(tap: UITapGestureRecognizer){
self.view.endEditing(true)
}
Upvotes: 0
Reputation: 575
There is no need to add UITapGestureRecognizer
as proposed above. UIViewContoller
already conforms to UIResponder
interface (legacy from Objective C), so you can override this method like this:
extension UIViewController {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.window?.endEditing(true)
super.touchesEnded(touches, with: event)
}
}
Upvotes: 4
Reputation: 35
Try the solution from Dimple Desai but add the gesture recognizer to the TableView or CollectionView or whatever is laying on top of your UIView. Then it should work.
Upvotes: 0
Reputation: 13557
Please create UIViewController
for dismiss keyboard througout application.
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
@objc func dismissKeyboard() {
view.endEditing(true)
}
}
Use above code in your UIViewController
file as below.
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
}
Update:
You can also use below code to dismiss keyboard from any class.
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
Upvotes: 2