Add filter button to UISearchController
Solution 1
I could create a search filter with a few lines of code. I hope it helps.
*I chose the bookmark button to apply filter icon; because I have already used cancel button for custom action.
First, you have to delegate searchBar to handle bookmark button click action. Then you should set properties as below. If you want to give custom position (default position is right side), you need to setPositionAdjustment.
searchController.searchBar.delegate = self
searchController.searchBar.showsBookmarkButton = true
searchController.searchBar.setImage(UIImage(named: "Sort"), for: .bookmark, state: .normal)
// MARK: You may change position of bookmark button.
//searchController.searchBar.setPositionAdjustment(UIOffset(horizontal: 0, vertical: 0), for: .bookmark)
Then, override searchBarBookmarkButtonClicked function inside your VC. You can handle click event inside this method.
func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) {
//showAlert, presentVC or whatever you want here
}
Also if you want to hide bookmark button while search controller is active, you need to apply control inside updateSearchResults method.
if searchController.isActive {
searchController.searchBar.showsBookmarkButton = false
} else {
searchController.searchBar.showsBookmarkButton = true
}
When searchController is not active:
When searchController is active:
Solution 2
Instead of customising the UISearchBar and complicating things, you can keep it simple by adding your own button beside SearchBar.
Set No the Shows cancel button option for SearchBar using
self.searchBar.showsCancelButton = true
OR
uncheck Shows cancel button option for SearchBar in StoryBoard
Add your own button beside SearchBar as shown below
And then accordingly add IBaction to the button and perform your actions in it.
Also in ideal case, it is not recommendable to put this view in Header of tableview. It will be better if it is above the tableview as also followed by Apple.
Solution 3
I tried lot of way's to customize searchbar but nothing helped me at last found a way to full-fill your requirement
let mysearchController = UISearchController(searchResultsController: nil)
mysearchController.searchBar.showsCancelButton = true
mysearchController.searchBar.barStyle = UIBarStyle.Black
for var subView1 in mysearchController.searchBar.subviews{
for var subView2 in subView1.subviews{
if subView2 .isKindOfClass(UIButton){
let customizedCancelButton:UIButton = subView2 as! UIButton
customizedCancelButton.enabled = true
customizedCancelButton.setTitle("", forState: UIControlState.Normal)
let image1 = UIImage(named: "Sort")
customizedCancelButton.setBackgroundImage(image1, forState: UIControlState.Normal)
customizedCancelButton.addTarget(self, action: "sort", forControlEvents: UIControlEvents.TouchUpInside)
}
}
}
above code is much simple to understand.
func sort(){
print("sort button fired!!!")
}
Solution 4
Updated for iOS 13, supports early versions of iOS, based on Gokul G answer.
Add extension file to project — UISearchControllerCancelButton.swift (View on gist.github.com):
extension UISearchController {
func cancelButton() -> UIButton? {
if #available(iOS 13.0, *) {
return findCancelButton13()
}
return findCancelButtonOld()
}
func findCancelButtonOld() -> UIButton? {
for subView in searchBar.subviews {
for v in subView.subviews {
if let button = v as? UIButton {
return button
}
}
}
return nil
}
@available(iOS 13.0, *)
func findCancelButton13() -> UIButton? {
for subView in searchBar.subviews {
for v in subView.subviews {
for b in v.subviews {
if let button = b as? UIButton {
return button
}
}
}
}
return nil
}
}
Use:
let controller = UISearchController(searchResultsController: nil)
controller.searchBar.showsCancelButton = true
if let button = controller.cancelButton() {
// Customize button
let iconImage = UIImage(named: "yourIconName")
button.isEnabled = true
button.setTitle("", for: .normal)
button.setBackgroundImage(iconImage, for: .normal)
button.addTarget(self, action: #selector(yourMethodName), for: .touchUpInside)
}
Method declaration for button touch event:
@objc func yourMethodName() {
print("Cancel button tap")
}
Related videos on Youtube
Comments
-
smnk over 1 year
I want to add a "filter" or "sort" button next to the
searchBar
inside aUISearchController
. I have already tried to add theUIButton
and thesearchbar
into aUIView
and set this as myUITableView tableView.tableHeaderView
This does not work because thetableView.tableHeaderView
get's set back to theUISearchBar
only when dismissing the controller. Here is an example of how I want it to look:-
Wain almost 8 yearsis there a particular reason you're using a search controller? are you open to not using it and filtering the table view directly?
-
JAL almost 8 yearsThis questions is too broad and lacks an MCVE.
-
-
smnk almost 8 yearsI don't thing you understood what I am looking for. I don't want to know how to filter a tableView but rather how to manage to get a filter Button right next to the search Bar (in a Search Controller ideally)
-
Wain almost 8 yearsThat's why I asked about losing the search controller. The problem you have is that the search controller presents a different view, so the header is configured differently. You should be able to just setup another header on the other view. I find that search controllers just add complexity for little real benefit. If you just have 1 view you have 1 header that is simple to configure and the focus management is simple too.
-
Alessign over 6 yearsGreat solution! Thanks.
-
heyfrank almost 6 yearsThis has problems when used together with UISearchController. When active, the searchbar view gets removed from its superview and placed above everything else to be sticky. So the custom button is gone while search is active...
-
heyfrank almost 6 yearsI tried this approach without an UISearchController, but then sometimes the cancel button is not working anymore. Instead of calling the
searchBarCancelButtonClicked
, the searchBar gets focused again :/ -
zach wilcox over 3 yearsI tried to use this method but my done button does show
-
Tilo Delau over 3 yearsHow do you tint the image? Mine is just grey.
-
Ali Mert Özdemir over 3 years@TiloDelau I think your navigation tint color is default (gray). You may change statusBar tint color as you wish.
-
Tilo Delau over 3 years@Ali I am using UIBarButtonItem.appearance().tintColor. Also tried searchController.searchBar.barTintColor = UIColor.white. Neither works. I can have the cancel (and back button) a specific color, this does not do it. I tweak a lot in the status bar and search bar but I cannot target this. And would prefer to target it specifically to show that some filters have been selected and are active. also tried //UINavigationBar.appearance().tintColor