I am developing an iPad app that has a large number of UIViewControllers, UITableViews (with cells with accessoryViews of UITextFields) etc, etc. Many of the UIViewControllers appear within a navigation hierarchy.
There are many different places where UITextFields appear, including as UITableViewCell accessoryViews.
I would like to devise an efficient strategy for dismissing the keyboard whenever the user touches outside the UITextField currently being edited. I have searched for keyboard dismiss techniques but have not yet found an answer that explains how a general keyboard dismiss strategy might work.
For example, I like this approach, where the following code is added to any ViewController:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"* * * * * * * * *ViewControllerBase touchesBegan");
[self.view endEditing:YES]; // dismiss the keyboard
[super touchesBegan:touches withEvent:event];
}
…but this technique does not deal with situations where, for example, a touch occurs within a UITableView which is on display. So, I’d need to add some code to call endEditing when a UITableView is touched etc, etc. Which means that my app will be liberally sprinkled with lots of code to dismiss the keyboard when various other UIElements are touched.
I guess I could just try and identify all the different places where touches need to be intercepted and the keyboard dismissed, but it seems to me that there may be a better design pattern somewhere for handling iOS keyboard dismiss events.
Can anyone share their experiences in this matter, and recommend a specific technique for generically handling keyboard dismissal across an entire app?
Many thanks
Your view hierarchy lives inside a
UIWindow. TheUIWindowis responsible for forwarding touch events to the correct view in itssendEvent:method. Let’s make a subclass ofUIWindowto overridesendEvent:.The window will need a reference to the current first responder, if there is one. You might decide to also use
UITextView, so we’ll observe notifications from both text fields and text views.The window will start observing the notifications when it’s initialized, and stop when it’s deallocated:
We’ll override
sendEvent:to “adjust” the first responder based on the event, and then call super’ssendEvent:to send the event normally.We don’t need to do anything about the first responder if there is no first responder. If there is a first responder, and it contains a touch, we don’t want to force it to resign. (Remember, there can be multiple touches simultaneously!) If there is a first responder, and a new touch appears in another view that can become the first responder, the system will handle that correctly automatically, so we also want to ignore that case. But if there is a first responder, and it doesn’t contain any touches, and a new touch appears in a view that can’t become first responder, we want to make the first responder resign.
Reporting whether an event contains a touch in the first responder is easy:
Reporting whether an event contains a new touch in a view that can’t become first responder is almost as easy:
Once you’ve implemented this class, you need to change your app to use it instead of
UIWindow.If you’re creating your
UIWindowinapplication:didFinishLaunchingWithOptions:, you need to#import "MyWindow.h"at the top of yourAppDelegate.m, and then changeapplication:didFinishLaunchingWithOptions:to create aMyWindowinstead of aUIWindow.If you’re creating your
UIWindowin a nib, you need to set the custom class of the window toMyWindowin the nib.