textFieldDidBeginEditing过早调用

时间:2012-11-12 14:31:20

标签: ios uitextfield autoscroll uitextfielddelegate

我有一个应用程序,在键盘显示的情况下我必须向上滚动。 为了获得键盘大小,我正在注册 UIKeyboardWillShowNotification 事件:

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

这确实有效,问题是,在调用 textFieldDidBeginEditing 之后调用它。因此,我无法获得实际的键盘大小,但只有在该字段已经处于编辑模式之后,这才会在首先注册此事件的整个目的。 我确定我已经调用 UIKeyboardWillShowNotification 而不是 UIKeyboardDidShowNotification ,虽然切换这两个会产生相同的结果: 首先调用delegate方法,然后调用通知方法。关于如何扭转局面的任何想法?目前我很难编码大小,这是非常糟糕的做法...

5 个答案:

答案 0 :(得分:2)

我可以建议一个GitHub存储库

https://github.com/hackiftekhar/IQKeyboardManager

答案 1 :(得分:1)

这是我为此用途编写的基类。它是UIViewController的子类 每当我想实现这样的行为时,我只是让我的视图控制器成为这个基类的子类。

顺便说一句 - 你是对的。键盘弹出后会调用textFieldDidBeginEditing,这就是为什么你要按照我班级的描述在键盘的回调方法中向上滚动。

另请注意,要实现此功能,您需要将整个视图嵌入到滚动视图中,并将滚动视图的IBOutlet连接到它。

如果您不使用故事板,请删除IBOutlet部件并将视图嵌入滚动视图并使用代码建立连接。

在此之后说这里是代码:

标题文件

#import <UIKit/UIKit.h>

@interface BaseViewControllerWithKeyboard : BaseViewController

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

@end

实施档案

#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

答案 2 :(得分:0)

我在XCode 5中打开了一个新项目,向UITextField添加了ViewController并连接了其代理人。

这是我唯一的代码:

- (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));
}

这是日志输出:

<强> Portraid:

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

<强>风景:

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

修改

关于在textFieldDidBeginEditing之前调用name:UIKeyboardWillShowNotification,我真的不明白为什么textField处于编辑模式会有区别,但有几种方法可以解决这个问题。

  1. 从textFieldShouldBeginEditing保存对textField的引用,并在myNotificationMethod中使用它,如果在textFieldShouldBeginEditing中被触发了。

  2. 如此使用UIResponder

  3. textFieldDidBeginEditing中的

    - &gt;保存对UIResponder的引用,并将UIResponder更改为不相关的临时值。在myNotificationMethod中执行您想要对textField执行的操作(不在编辑模式\第一响应程序中),完成后将其设为主UIResponder

答案 3 :(得分:0)

根据Apple文档,在显示键盘之前调用 UIKeyboardWillShowNotification ,而在文本字段成为第一响应者之后立即调用 UITextFieldDidBeginEditing 。显示键盘的过程在文本字段成为第一响应者后 后启动,并且仅在键盘尚未显示时启动。这意味着将在 UITextFieldDidBeginEditing 之后调用 UIKeyboardWillShowNotification 。因此,不会过早调用 UITextFieldDidBeginEditing

如果您只想向上滚动以便文本字段不会隐藏在键盘下,您只需将滚动视图的内容偏移设置为 UITextFieldShouldBeginEditing中的文本字段的y-origin UITextFieldDidBeginEditing

答案 4 :(得分:0)

老问题,但今天我遇到了同样的问题。我已经构建了一个“脏”的解决方法,不会强迫我硬编码键盘大小。我只是在viewDidAppear(注意 - Swift)中执行了以下操作:

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

这会触发 UIKeyboardWillShowNotification ,您可以从通知中获取键盘大小并将其存储在属性中。希望这对某人有所帮助,它在我的案例中起作用。