textFieldDidBeginEditing is called prematurely

I have an application in which I have to scroll up in case of the keyboard showing. to get the keyboard size, I'm registering the UIKeyboardWillShowNotification event like so:

   [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(keyboardWillShow:)
     name:UIKeyboardWillShowNotification
     object:self.view.window]

This does work, the problem is, it is being called after the textFieldDidBeginEditing was called. So, I can't get the actual keyboard size, but only after the field is already in edit mode, which defeats the whole purpose of registering this event on the first place. I'm sure I've called the UIKeyboardWillShowNotification and not the UIKeyboardDidShowNotification , although switching these two yield the same results: first call was made to the delegate method and only then to the notification method. Any idea on how to turn this around? Currently I'm hard coding the size, which is very bad practice...


May I suggest a GitHub repository

https://github.com/hackiftekhar/IQKeyboardManager


Here is a base class I have written for this use exactly.It is a subclass of UIViewController Whenever I want to implement such behaviour I just make my view controller a sub class of this base class.

BTW - You are right. textFieldDidBeginEditing is called after keyboard shows up which is why you want to scroll up in the call backs method of the keyboard as described in my class.

Also please note that for this to work you need to embed your entire view in a Scroll View and connect the IBOutlet of the scroll view to it.

If you are not using story board remove the IBOutlet part and embed your view in a scroll view and make the connection in code.

After this said here is the code:

Header File

#import <UIKit/UIKit.h>

@interface BaseViewControllerWithKeyboard : BaseViewController

@property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
@property (nonatomic, strong) UITextField *activeField;

@end

Implementation File

#import "BaseViewControllerWithKeyboard.h"

@interface BaseViewControllerWithKeyboard ()

@end

@implementation BaseViewControllerWithKeyboard

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self registerForKeyboardNotifications];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];

}

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your app might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, _activeField.frame.origin) ) {
        [self.scrollView scrollRectToVisible:_activeField.frame animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;
}

@end

I opened a new project in XCode 5, added a UITextField to the ViewController and connected its delegate.

This is my only code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myNotificationMethod:) name:UIKeyboardWillShowNotification object:nil];
}

- (void)myNotificationMethod:(NSNotification*)notification
{
    NSDictionary* keyboardInfo = [notification userInfo];
    NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
    NSLog(@"Rect: %@",NSStringFromCGRect(keyboardFrameBeginRect));
}

Here's the log output:

Portraid:

 Rect: {{0, 480}, {320, 216}}

Landscape:

 Rect: {{-162, 0}, {162, 480}}

Edit:

Regarding textFieldDidBeginEditing being called before name:UIKeyboardWillShowNotification , I don't really understand why there's a difference if the textField is in edit mode or not but there are a few ways to solve this.

  • saving a reference to textField from textFieldShouldBeginEditing and use it inside myNotificationMethod if in did textFieldShouldBeginEditing was triggered.

  • Playing around with UIResponder like so:

  • in textFieldDidBeginEditing -> Save a reference to the UIResponder and change the UIResponder to a temp irrelevant one. in myNotificationMethod do what ever you want to do to the textField (that is not in edit mode first responder), when you are done make it your main UIResponder .

    链接地址: http://www.djcxy.com/p/11444.html

    上一篇: C ++

    下一篇: textFieldDidBeginEditing被提前调用