Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't hide keyboard in UIViewController stack when UIAlertView is on screen

I just spent most of a day tracking down a very strange case where calling resignFirstResponder on the active UITextField did not hide the keyboard, even though the textfield was the first responder. This happens when I push a view controller on top of another view controller with an active text field. The keyboard goes away (as expected). But if I bring the keyboard back by touching a textfield in the 2nd view controller, subsequent calls to resignFirstResponder have no effect.

Here's simple code to reproduce the issue. This code is a view controller with a nav bar button to hide the keyboard, and another to push another copy of itself (with a confirmation UIAlertView). The first copy works without problem. However, if you push a 2nd copy (when the first copy has a visible keyboard) it is impossible to dismiss the keyboard. This only happens if there is a UIAlertView (the confirmation) on the screen when the 2nd copy is pushed. If you remove the #define ALERT line, everything works.

Does anyone know what is happening here? It looks like the UIALertView window is somehow interfering with the keyboard and keeping it's window from disappearing, which then confuses the next view. Is there any solution here other than pushing the 2nd view controller on a timer after the UIALertView is gone?

Sorry for the complex description. This is runnable code. I hope that the code is clear.

@implementation DemoViewController

- (id) init {
    if (!(self = [super init])) 
        return nil;

    return self; 
}

- (void) dealloc {
    [_inputTextfield release];
    [super dealloc];
}

- (void) loadView {
    UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];

    _inputTextfield = [[UITextField alloc] initWithFrame:CGRectMake(0., 0., 320., 44.)];
    _inputTextfield.borderStyle = UITextBorderStyleRoundedRect;
    _inputTextfield.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
    _inputTextfield.keyboardAppearance = UIKeyboardAppearanceAlert;
    _inputTextfield.autocapitalizationType = UITextAutocapitalizationTypeNone;
    _inputTextfield.autocorrectionType = UITextAutocorrectionTypeNo;
    _inputTextfield.keyboardType = UIKeyboardTypeDefault;
    [view addSubview:_inputTextfield];

    self.view = view;
    [view release];
}

- (void) viewWillAppear:(BOOL) animated {
    [super viewWillAppear:animated];

    UIButton *downButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [downButton setTitle: @"keyboard down" forState:UIControlStateNormal];
    [downButton addTarget:self action:@selector(downButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    [downButton sizeToFit];    
    self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:downButton] autorelease];

    UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [nextButton setTitle: @"next" forState:UIControlStateNormal];
    [nextButton addTarget:self action:@selector(nextButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    [nextButton sizeToFit];
    self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:nextButton] autorelease];;

}

- (void) viewWillDisappear:(BOOL) animated {
[super viewWillDisappear:animated];
    [_inputTextfield resignFirstResponder];
}

- (void) downButtonPressed:(id)sender {
    [_inputTextfield resignFirstResponder];
}

#define ALERT

- (void) alertView:(UIAlertView *) alertView didDismissWithButtonIndex:(NSInteger) buttonIndex {
    if (alertView.cancelButtonIndex == buttonIndex) {
        return; 
    }
    [self _nextButtonPressed];
}

- (void) _nextButtonPressed {
    DemoViewController *nextViewController = [[DemoViewController alloc] init];    
    [self.navigationController pushViewController:nextViewController];
    [nextViewController release];
}

- (void) nextButtonPressed:(id)sender {
#ifdef ALERT   
    UIAlertView *alert = [[UIAlertView alloc] init];
    alert.message = @"Next view?";  
    alert.cancelButtonIndex = [alert addButtonWithTitle:@"No"];
    [alert addButtonWithTitle:@"Yes"];
    alert.delegate = self;
    [alert show];
    [alert release];
#else   
    [self _nextButtonPressed];    
#endif
}
like image 658
wombat57 Avatar asked Oct 10 '22 15:10

wombat57


1 Answers

If you had bad luck resigning your first responders, here are a few solutions that might help:

  1. Determine who has remained the first responder after your last call to resign first responder.

  2. Try resigning all first responders by a single call to self.view (container view)

    [self.view endEditing:YES];
    
  3. ONLY if you've tried all the above methods and none worked, consider using this workaround.

    -(BOOL)textViewShouldEndEditing:(UITextView *)textView {
      NSArray *wins = [[UIApplication sharedApplication] windows];
      if ([wins count] > 1) {
        UIWindow *keyboardWindow = [wins objectAtIndex:1];
        keyboardWindow.hidden = YES;
      }
      return YES;
    }
    
like image 198
Alon Amir Avatar answered Oct 16 '22 08:10

Alon Amir