views:

1449

answers:

2

Does anyone know how to cancel (resign First Responder) out of a UISearchBar when you tap below the search text box and above the keyboard? Can anyone help post some code to handle this?

Thanks

A: 

First, you need a reference to the search bar. Let's assume that your controller object has an object reference UISearchBar *theSearchBar, and that you assign it when you create the UISearchBar object.

Next, you need to detect that the containing view has been touched. The view that is touched "knows", but you need get that information to the controller. Sadly, Apple didn't provide a simple way to do this, but it's not that hard either.

My solution is to replace the standard UIView that a UIViewController object normally creates with a UIControl, and then make the UIViewController respond to touch events.

MainController.m

- (void) loadView {
    UIControl *control = [[UIControl alloc] initWithFrame: <desired frame>];
[control addTarget: self action: @selector(touchUpInside) 
             forControlEvents: UIControlEventTouchUpInside];
       // or touch down events, or whatever you like
    self.view = control;
    [control release];
}

- (void) viewDidLoad {
    [super viewDidLoad];
    theSearchBar = [[UISearchBar alloc] initWithFrame: <desired frame>];

    // insert code to finish customizing the search bar

    [self.view addSubview: theSearchBar];
}

- (void) touchUpInside {
    if [theSearchBar isFirstResponder] {
        // grab any data you need from the search bar
        [theSearchBar resignFirstResponder];
    }
}

MainController.h

@interface MainController : UIViewController
{
    UISearchBar *theSearchBar;
}

Clarification:

There is only a single object -- let's call the class MainController -- which is a subclass of UIViewController. All of the methods listed above are implemented in MainController. theSearchBar is declared as a UISearchBar* in the .h file.

Are you defining your view and controller using Interface Builder? If so, I suggest you learn how to NOT use it -- once you get into the kind of tricks we are discussing here, it becomes more of a hindrance than a help -- I don't use it at all, ever.

Amagrammer
How do I get the reference to the searchBar from the touchUpInside event? I have touchUpInside in the viewcontroller class containing the searchbar.
Zap
You mean, in order to invoke resignFirstResponder? You already have it if you saved it as a reference when you created it.
Amagrammer
I'm a little confused. Is the above code supposed to be in a separate view controller from the one where I created the search bar? Also why do you create a UIControl instead of a UISearchBar in your loadView routine?
Zap
Yes, you are confused, and probably because I didn't put in enough code for you. I will edit my response.
Amagrammer
Thanks for more details. I tried following your update very specifically but now I'm getting the error:error: 'searchBar' undeclared (first use in this function). FYI, searchBar is the name of the UISearchBar *searchBar declared in my viewDidLoad event. Do I need to declare searchBar globally?
Zap
Not globally, but in the MainController.h file (or whatever you call it). I will put in just a bit more above to show you what I mean; however, if you REALLY don't understand this, I think you need to read the documentation in a bit more detail.
Amagrammer
I've already done all the things you mentioned. Now, when I build and run, it says loading more than a hundred thousand stack frames. The debugger breaks to some machine assembly and the simulator displays a black screen. When i comment out your loadView routine above, it runs fine. Please advise.
Zap
It has to do with how you are assigning self.view in loadView. I need to double-check the syntax -- please give me a bit to do so.
Amagrammer
Duh. I made a silly mistake. viewDidLoad has no parameters -- it's only those like viewDidAppear, etc. that have "animated" as a parameter. Try fixing as shown above.
Amagrammer
I tried, but am still getting an exception. I'm using iphone sdk 3.0.
Zap
Okay, at this point, I need to see your actual code. Otherwise, there isn't much I can do.
Amagrammer
Is there an email I can send you my code?
Zap
I'd prefer not to post my email here. Would it really be so bad to post just the methods that are involved?
Amagrammer
+1  A: 

An alternative idea I got from iphonedevbook, sample code project 04, was to use one big transparent button that lies behind all other controls which does nothing but resign all first responders if tapped. I.e. if the user taps anywhere where there isn't a more important control - which is the intuitive behavior - the search bar and keyboard disappear.

Hauke
This is effectively the same as my suggestion above. It might be a bit simpler to implement.
Amagrammer
Thank you Hauke! Creating the transparent button and handling the touchup event to resign the first responder did the trick.
Zap
One other question I now have is let's say I have a view containing an mkmapview behind that transparent button. How can i can reactivate the map once the searchBar has gone away?
Zap