textFieldDidBeginEditing is called prematurely

荒凉一梦 提交于 2019-12-04 05:11:39

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.

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

  2. 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.

According to the Apple documentation UIKeyboardWillShowNotification is called just before the keyboard will be shown, while UITextFieldDidBeginEditing is called just after the text field becomes first responder. The process to show the keyboard is started after the text field becomes first responder, and only if the keyboard is not already shown. This means UIKeyboardWillShowNotification will be called after UITextFieldDidBeginEditing. So UITextFieldDidBeginEditing is not called prematurely.

If you just want to scroll up so the text field won't be hidden under the keyboard, you can just set the content offset of the scroll view to the y-origin of the text field in UITextFieldShouldBeginEditing or UITextFieldDidBeginEditing.

Old question, but I ran into the same issue today. I have built a little "dirty" workaround that does not force me to hardcode the keyboard size. I simply did the following in viewDidAppear (attention - Swift):

 override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.infoTextField.becomeFirstResponder()
    self.infoTextField.resignFirstResponder()
}

This triggers the UIKeyboardWillShowNotification and you can get the keyboard size from the notification and store it in a property. Hope this helps someone, it worked in my case.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!