ConfusedNoob
ConfusedNoob

Reputation: 10196

UITableView - resign first responder on outside touch

I have a UITableView with an associated UITableViewController. However, I've modified the table to also have a view with a textfield subview.

As always, I want the keyboard to disappear when the user hits 'done' (easy) and when they touch anywhere else on screen other than the textfield (hard, stuck!).

The normal way to achieve this is to change the class to UIControl so it can handle actions... but I can't do this for my UITableView/UITableViewController combination.

How can I solve this problem?

Upvotes: 2

Views: 9812

Answers (4)

PicoCreator
PicoCreator

Reputation: 10174

Using alloc breaks with ARC enabled

Just add the following to the viewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    //where text field is a @property (nonatomic,retain) IBOutlet to your textfield
    [textField resignFirstResponder]; 
}

Upvotes: 2

Eyal
Eyal

Reputation: 10828

U can handle user touches by adding a UITapGestureRecognizer to your view.
For example if u don't want to enable row selection in your tableView u call self.tableView.allowsSelection = NO;
But if u still want to detect user touches u add a UITapGestureRecognizer to your tableView (or to tableView.superview).
U can have more control if u implement the UIGestureRecognizerDelegate, this way u can detect and then choose witch touches to receive and witch not.
To do that just add this code to your UITableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.tableView.allowsSelection = NO;

    UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTapped:)];
    tgr.delegate = self;
    [self.tableView addGestureRecognizer:tgr]; // or [self.view addGestureRecognizer:tgr];
    [tgr release];
}    

- (void)viewTapped:(UITapGestureRecognizer *)tgr
{
    NSLog(@"view tapped");  
    // remove keyboard
}

// this is optional, it let u choose witch touches to receive, for example here I'm checking if user has tapped on a textField

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isKindOfClass:[UITextField class]]) {
        NSLog(@"User tapped on UITextField");
    }
    return YES; // do whatever u want here
}

Upvotes: 6

Olaf
Olaf

Reputation: 3042

When a row is tapped the didSelectRowAtIndexPath is called. If a textField located inside inside a row is tapped then the textfield delegate is called.

So in addition to your done button method, in didSelectRowAtIndexPath add a check for the text field being first responder and ask it to resign. Assuming a the selected indexPath is not the row of the textfield.

Upvotes: 0

Bogdan Andresyuk
Bogdan Andresyuk

Reputation: 523

A normal practice is to put a custom UIButton( it becomes visible only when uitextfield begins editing ) behind keyboard view, and when user clicks on screen he actually clicks on that button, and associated selector can resign first responder.

-(void) closeKeyboard:(UIButton *) b {
    [self.view endEditing:YES]; //assuming self is your top view controller.
    [b setHidden:YES];  
}

Using endEditing is better, cause it loops through all subviews and looks for current first responder.

Upvotes: 4

Related Questions