9

On the UISearchBar, there's an X element that allows you to clear all of the contents at once. Is there a way to get notified when this happens?

UISearchBarDelegate::searchBarCancelButtonClicked is fired only when the "Cancel" button is tapped.

Justin Galzic
  • 3,951
  • 6
  • 28
  • 39
  • https://stackoverflow.com/questions/29135594/uisearchbar-x-button-pressed/59105874#59105874 :):) – Mohan Nov 29 '19 at 14:09

4 Answers4

7

The UISearchBar doesn't have a delegate method for this event. You can nearly get what you want by implementing the textDidChange: method of the callback delegate and checking for an empty string.

I don't recommend it, but there is another possible way. The UISearchBar is composed of a UITextField, which does have a delegate method that is called when the user taps the clear button (textFieldShouldClear:). You can get the UITextField by traversing the UISearchBar's child views:

(this is in the context of a derived UISearchBar class)

- (UIView*) textField
{
    for (UIView* v in self.subviews)
    {
        if ( [v isKindOfClass: [UITextField class]] )
            return v;
    }

    return nil;
}

from here, you could re-assign the UITextField delegate to your own implementation, taking care to forward delegate calls to the old delegate. This way you could intercept textFieldShouldClear:. Or if it turns out the UISearchBar is the delegate for the UITextField it contains you could swizzle the call to textFieldShouldClear:... Not ideal, clearly, but technically feasible.

Fry
  • 6,235
  • 8
  • 54
  • 93
TomSwift
  • 39,369
  • 12
  • 121
  • 149
  • Why do you not recommend implementing the textDidChange and checking for an empty string? – Justin Galzic Nov 08 '10 at 18:06
  • I think this would be a fine way to do it. But it's not exactly what he's asking for since the text can become an empty string in other ways than by clicking the 'x'. Like backspace.. So if he wants to be notified whenever the 'x' is clicked, then this would result in a false positive. – TomSwift Nov 08 '10 at 23:06
2

I had the same issue and I solved this issue by using this function.

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 
{
    // This method has been called when u enter some text on search or Cancel the search.
    if([searchText isEqualToString:@""] || searchText==nil) {
        // Nothing to search, empty result.

       [UIView animateWithDuration:0.2 animations:^ {
        //Reposition search bar 
        [_searchBar setFrame:CGRectMake(230, 26, 43, 44)];
        [_searchBar setNeedsLayout];
       }];
    }
}
Chitra Khatri
  • 1,260
  • 2
  • 14
  • 31
Akhtar
  • 3,172
  • 5
  • 19
  • 21
1

Here is an answer from a previous question, this should do exactly what you want. UISearchbar clearButton forces the keyboard to appear

Community
  • 1
  • 1
Tozar
  • 976
  • 9
  • 20
0

Here is "Method Swizzling" solution.

  1. Create a new Category of UISearchBar. This category create a new method and swizzle method between -(BOOL)textFieldShouldClear:(UITextField *)textField; and -(BOOL)jbm_textFieldShouldClear:(UITextField *)textField in runtime.
  2. Customize a new Protocol of UISearchBarDelegate in order to add a new method - (void)searchBarClearButtonClicked:(id)sender;

UISearchBar+JMBTextFieldControl.h

    @protocol UISearchBarWithClearButtonDelegate <UISearchBarDelegate>
    @optional
    - (void)searchBarClearButtonClicked:(id)sender;
    @end

    @interface UISearchBar (JMBTextFieldControl)
    @end

UISearchBar+JMBTextFieldControl.m

    #import "UISearchBar+JMBTextFieldControl.h"
    #import <objc/runtime.h>

    @implementation NSObject (Swizzling)

    + (void)brc_swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector
    {
        Method origMethod = class_getInstanceMethod(self, origSelector);
        Method newMethod = class_getInstanceMethod(self, newSelector);

        if(class_addMethod(self, origSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
            class_replaceMethod(self, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
        else
            method_exchangeImplementations(origMethod, newMethod);
    }
    @end

    @implementation UISearchBar (JMBTextFieldControl)

    + (void)load {
        [self brc_swizzleMethod:@selector(textFieldShouldClear:) withMethod:@selector(jbm_textFieldShouldClear:)];
    }

    - (id<UISearchBarWithClearButtonDelegate>)jbm_customDelegate {
        if( [[self delegate] conformsToProtocol:@protocol(UISearchBarWithClearButtonDelegate)] )
            return (id<UISearchBarWithClearButtonDelegate>)[self delegate];
        else
            return nil;
    }

    - (BOOL)jbm_textFieldShouldClear:(UITextField *)textField
    {
        if ( [[self jbm_customDelegate] respondsToSelector:@selector(searchBarClearButtonClicked:)] )
            [[self jbm_customDelegate] searchBarClearButtonClicked:self];

        return [self jbm_textFieldShouldClear:textField];
    }

    @end

Reference

  1. Dave DeLong - How to add a method to an existing protocol in Cocoa?

  2. Nikolay Vlasov - CCBottomRefreshControl

Community
  • 1
  • 1
Jim Yu
  • 1,236
  • 11
  • 10