43

How handle the event when press the 'x' button?

I try this method but not works.

-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{

}

enter image description here

shim
  • 9,289
  • 12
  • 69
  • 108
Fabio
  • 1,913
  • 5
  • 29
  • 53

16 Answers16

45

I don't think there's an easy way to hook into the X button.

However, you can hook into its direct consequence: cleared text.

Try this:

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText == "" {
        print("UISearchBar.text cleared!")
    }
}

The side effect is this also gets called when you manually clear your text.

Eric Johnson
  • 1,087
  • 1
  • 11
  • 16
  • 8
    A more accurate description is that using this method to detect a clear button press is a hack. I can't believe Apple hasn't fixed this after all these years. – funct7 Oct 03 '18 at 05:29
  • if it doesn't work, adding _ should do it. That is: (_ searchBar: UISearchBar, textDidChange searchText: String) – Emil Mar 10 '21 at 03:40
  • With this you can't differentiate between deleting text with keyboard and pressing the x button – lolelo Aug 18 '21 at 15:11
21

A rather hacky way to do it but this works.

private var didTapDeleteKey = false

func searchBar(_ searchBar: UISearchBar,
               shouldChangeTextIn range: NSRange,
               replacementText text: String) -> Bool
{
    didTapDeleteKey = text.isEmpty

    return true
}

func searchBar(_ searchBar: UISearchBar,
               textDidChange searchText: String)
{
    if !didTapDeleteKey && searchText.isEmpty {
        // Do something here
    }

    didTapDeleteKey = false
}

The success of this code hinges on the fact that when tapping the clear button of the search bar, searchBar(_:shouldChangeTextIn:replacementText:) -> Bool is not called. Instead when the delete button of the keyboard is tapped, the method is called.

funct7
  • 3,407
  • 2
  • 27
  • 33
20

Swift 5.2, Xcode 11.4

This one worked for me.

if let searchTextField = self.categoriesSearchBar.value(forKey: "searchField") as? UITextField , let clearButton = searchTextField.value(forKey: "_clearButton")as? UIButton {

     clearButton.addTarget(self, action: #selector(self.yourFunction), for: .touchUpInside)
}
Kedar Sukerkar
  • 1,410
  • 1
  • 16
  • 22
9

Simplest solution in Swift 5.0

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.isEmpty {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            searchBar.resignFirstResponder()
        }
    }
}
Dejan
  • 139
  • 1
  • 5
  • Read the docs in the header.... - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText; // called when text changes (including clear) – zumzum Jun 11 '20 at 20:11
7

As stated in Apple's documentation there is a delegate method textFieldShouldClear(_:) in UITextFieldDelegate.

The text field calls this method in response to the user pressing the built-in clear button.

So

  1. conform to UITextFieldDelegate
  2. set the delegate of your searchBar's text field
  3. implement textFieldShouldClear(_:) method
class MyClass: UITextFieldDelegate {
   weak var seachBar: UISearchBar!

   override func viewDidLoad() {
       if #available(iOS 13.0, *) {
          searchBar.searchTextField.delegate = self
       } else {
          searchBar.textField.delegate = self
       }
   }

   func textFieldShouldClear(_ textField: UITextField) -> Bool {
        // your code
        return true
    }
}
eja08
  • 4,600
  • 3
  • 13
  • 19
4

I had the same issue, tried to solve it with accessing searchBar's subview textField but it caused my app crash, and with a last effort i found this post.

Another issue was that,

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText

is being called twice when cancel button clicked, see also this.

And lastly what i did is;

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if (![searchText isEqualToString:self.searchText]) {
        self.searchText = searchText;
        return;
    }
    NSLog(@"Clear clicked");
}

This solved my issue.

Community
  • 1
  • 1
Eray Diler
  • 1,095
  • 1
  • 10
  • 17
4
self.mySearchBar.searchTextField.delegate = self

    extension myViewController: UISearchTextFieldDelegate {

    func textFieldShouldClear(_ textField: UITextField) -> Bool {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            self.mySearchBar.searchTextField.resignFirstResponder()
        }
        return true
    }
}
David
  • 3,285
  • 1
  • 37
  • 54
Mohan
  • 361
  • 1
  • 3
  • 11
3

I think the simplest solution to this question is:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
     if searchText.isEmpty {
             DispatchQueue.main.async {
                 searchBar.resignFirstResponder()
             }
 }
Sam
  • 488
  • 1
  • 5
  • 14
3

I had the same issue and it was solve like that: In search controller that inherits from UISearchController I added conformance to UITextFieldDelegate.

Then in init method the following line was addd:

searchBar.searchTextField.delegate = self

And implementing

func textFieldShouldClear(_ textField: UITextField) -> Bool

allows to achieve the information that clear button was pressed

patmar
  • 221
  • 1
  • 12
2

This works for me

-(UITextField*)getUITexfieldInUISearchBar:(UIView*)aSearchBar{
UITextField *searchBarTextField;
for (UIView *subView in [aSearchBar subviews]){
    if ([subView isKindOfClass:[UITextField class]])
    {
        searchBarTextField = (UITextField *)subView;
        [searchBarTextField setDelegate:self];
        break;

    }else if ([subView isKindOfClass:[UIView class]]){
        [self getUITexfieldInUISearchBar:subView];
    }
}
  return searchBarTextField;
}

And you can use the TextFields Delegate

- (BOOL)textFieldShouldClear:(UITextField *)textField {
   //Do something here...
}
2
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if (searchText.length == 0) {
         //clear button (x) on the search bar is cliecked, so clear the table
        [self clearTable];
    }
}
Mona
  • 5,939
  • 3
  • 28
  • 33
0
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String){
    print("searchText: \(searchText)")
    if searchText.count > 0
    {
        // Show ur content
    }
    else
    {
        // Hide your content
    }
}
Soumya Ranjan
  • 4,817
  • 2
  • 26
  • 51
0

... just works

if(searchText.length==0||searchText==nil){
    [self.searchBar resignFirstResponder];
    [NSTimer scheduledTimerWithTimeInterval:0.1
                                     target:self
                                   selector:@selector(hideKeyboard)
                                   userInfo:nil
                                    repeats:NO];
}

- (void)hideKeyboard{
   [self.searchBar resignFirstResponder];
}
0

Until apple releases a proper delegate method for clear button event handling this will work as of Xcode 12. Requires: >=iOS13

Get a reference to the searchBar clearButton if possible.

UIButton *searchBarTextFieldClearButton = [self.searchBar.searchTextField valueForKey:@"_clearButton"];
if (searchBarTextFieldClearButton) {
    [searchBarTextFieldClearButton addTarget:self action:@selector(searchTextFieldClearButtonTapHandler) forControlEvents:UIControlEventTouchUpInside];
}

Swift:

extension UISearchTextField {
   var clearButton: UIButton? {
      return value(forKey: "_clearButton") as? UIButton
   }
}
searchBar.searchTextField.clearButton.addTarget(self, #selector(handler), .touchUpInside) //bllah

Very important to keep in mind that your "action - searchTextFieldClearButtonTapHandler" gets called last. That is, after the delegate method - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText

-1

You can hook up to "Cancel button" clicked event by conforming to "UISearchBarDelegate" and then implement "searchBarCancelButtonClicked" method

Vrutin Rathod
  • 900
  • 1
  • 12
  • 16
  • 9
    Nope, the cancel button is a different button which appears when setting `searchBar.showsCancelButton = true`. – mattsson Aug 28 '18 at 09:54
  • 1
    Cancel button is different and "x" button is different. Did you check before posting if the "searchBarCancelButtonClicked" method is triggered on click of "x" button? – Tejas Mar 13 '20 at 08:07
-2
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {


    let inputString = searchText.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)

    if inputString.characters.count > 0
    {

    }
    else
    {
          //Write code here for Clear button action
    }
}
bruno
  • 32,421
  • 7
  • 25
  • 37
Urvish Modi
  • 1,118
  • 10
  • 11