我目前正在开发一个具有单一视图的iPhone应用程序,该应用程序有多个UITextFields可供输入.当键盘显示时,它会覆盖底部的文本字段.因此,我添加了相应的textFieldDidBeginEditing:方法,将视图向上移动,效果非常好:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    if ( ( textField != inputAmount ) && ( textField != inputAge ) ) {
        NSTimeInterval animationDuration = 0.300000011920929;
        CGRect frame = self.view.frame;
        frame.origin.y -= kOFFSET_FOR_KEYBOARD;
        frame.size.height += kOFFSET_FOR_KEYBOARD;
        [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
        [UIView setAnimationDuration:animationDuration];
        self.view.frame = frame;
        [UIView commitAnimations];      
    }
}

此方法判断消息源是否是键盘显示时可见的文本字段之一,如果不是,则向上移动视图.

我还添加了textFieldDidEndEnditing:方法,该方法再次向下移动视图(并根据更改的输入更新一些模型对象):

- (void)textFieldDidEndEditing:(UITextField *)textField {
    if ( ( textField != inputMenge ) && ( textField != inputAlter ) ) {
        NSTimeInterval animationDuration = 0.300000011920929;
        CGRect frame = self.view.frame;
        frame.origin.y += kOFFSET_FOR_KEYBOARD;
        frame.size.height -= kOFFSET_FOR_KEYBOARD;
        [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
        [UIView setAnimationDuration:animationDuration];
        self.view.frame = frame;
        [UIView commitAnimations];      
    }
    // Additional Code
}

然而,这个解决方案有一个简单的缺陷:当我编辑完一个"隐藏"文本字段并touch 另一个文本字段时,键盘消失,视图下移,视图再次上移,键盘再次出现.

是否有可能防止键盘在两次编辑之间消失和重新出现(对"隐藏"文本字段进行编辑,以便仅当所选文本字段从键盘隐藏的文本字段更改为不隐藏的文本字段时,视图才会移动)?

推荐答案

此解决方案基于ComSubVie的解决方案.

优势:

  • 它支持设备旋转——适用于所有方向;
  • 它不会硬编码动画持续时间和曲线的值,而是从键盘通知中读取它们;
  • 它使用UIKeyboardWillShowNotification而不是UIKeyboardDidShowNotification来同步键盘动画和自定义动作;
  • 它没有使用不推荐的UIKeyboardBoundsUserInfoKey
  • 它可以通过按国际键来调整键盘大小;
  • 通过注销键盘事件修复了内存泄漏;
  • 所有键盘处理代码都封装在一个单独的类中——KBKeyboardHandler
  • 灵活性——KBKeyboardHandler级可能很容易扩展/修改,以更好地满足特定需求;

限制:

  • 适用于iOS 4及以上版本,需要稍加修改以支持旧版本;
  • 它适用于单个UIWindow的应用程序.如果使用多个UIWindows,可能需要修改retrieveFrameFromNotification:方法.

用法:

包括KBKeyboardHandler.h、 键盘处理器.m和KBKeyboardHandlerDelegate.在你的项目中.在视图控制器中实现KBKeyboardHandlerDelegate协议——它由一个方法组成,当显示、隐藏或更改键盘大小时将调用该方法.实例化KBKeyboardHandler并设置其委托(通常为self).见下面的样本MyViewController.

KBKeyboardHandler.h:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@protocol KBKeyboardHandlerDelegate;

@interface KBKeyboardHandler : NSObject

- (id)init;

// Put 'weak' instead of 'assign' if you use ARC
@property(nonatomic, assign) id<KBKeyboardHandlerDelegate> delegate; 
@property(nonatomic) CGRect frame;

@end

KBKeyboardHandler.m:

#import "KBKeyboardHandler.h"
#import "KBKeyboardHandlerDelegate.h"

@implementation KBKeyboardHandler

- (id)init
{
    self = [super init];
    if (self)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillShow:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:nil];

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

    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

@synthesize delegate;
@synthesize frame;

- (void)keyboardWillShow:(NSNotification *)notification
{
    CGRect oldFrame = self.frame;    
    [self retrieveFrameFromNotification:notification];

    if (oldFrame.size.height != self.frame.size.height)
    {
        CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width,
                                  self.frame.size.height - oldFrame.size.height);
        if (self.delegate)
            [self notifySizeChanged:delta notification:notification];
    }
}

- (void)keyboardWillHide:(NSNotification *)notification
{
    if (self.frame.size.height > 0.0)
    {
        [self retrieveFrameFromNotification:notification];
        CGSize delta = CGSizeMake(-self.frame.size.width, -self.frame.size.height);

        if (self.delegate)
            [self notifySizeChanged:delta notification:notification];
    }

    self.frame = CGRectZero;
}

- (void)retrieveFrameFromNotification:(NSNotification *)notification
{
    CGRect keyboardRect;
    [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect];
    self.frame = [[UIApplication sharedApplication].keyWindow.rootViewController.view convertRect:keyboardRect fromView:nil];
}

- (void)notifySizeChanged:(CGSize)delta notification:(NSNotification *)notification
{
    NSDictionary *info = [notification userInfo];

    UIViewAnimationOptions curve;
    [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];

    NSTimeInterval duration;
    [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];

    void (^action)(void) = ^{
        [self.delegate keyboardSizeChanged:delta];
    };

    [UIView animateWithDuration:duration
                          delay:0.0
                        options:curve
                     animations:action
                     completion:nil];    
}

@end

KBKeyboardHandlerDelegate.h:

@protocol KBKeyboardHandlerDelegate

- (void)keyboardSizeChanged:(CGSize)delta;

@end

样本MyViewController.h:

@interface MyViewController : UIViewController<KBKeyboardHandlerDelegate>
...
@end

样本MyViewController.m:

@implementation MyViewController
{
    KBKeyboardHandler *keyboard;
}

- (void)dealloc
{
    keyboard.delegate = nil;
    [keyboard release];
    [super dealloc];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    keyboard = [[KBKeyboardHandler alloc] init];
    keyboard.delegate = self;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    keyboard.delegate = nil;
    [keyboard release];
    keyboard = nil;
}

- (void)keyboardSizeChanged:(CGSize)delta
{
    // Resize / reposition your views here. All actions performed here 
    // will appear animated.
    // delta is the difference between the previous size of the keyboard 
    // and the new one.
    // For instance when the keyboard is shown, 
    // delta may has width=768, height=264,
    // when the keyboard is hidden: width=-768, height=-264.
    // Use keyboard.frame.size to get the real keyboard size.

    // Sample:
    CGRect frame = self.view.frame;
    frame.size.height -= delta.height;
    self.view.frame = frame;
}

更新:修复了iOS 7警告,谢谢@weienv.

Objective-c相关问答推荐

Objective C:给定一个Class id,我可以判断这个类是否实现了某个协议吗?还是有一定的 Select 器?

如何在 Cocoa 中创建字符串的 MD5 哈希?

自动属性合成 (@property) 和继承

是否需要 ARC 中的 NSNotificationCenter removeObserver?

iOS 编译错误:CDVCommandDelegateImpl没有可见的@interface 声明 Select 器执行:

iOS 正确使用 @weakify(self) 和 @strongify(self)

将子视图添加到 UIButton

MKMapView MKPointAnnotation 点击​​事件

iOS 7 - 键盘动画

NSManagedObjectContext:异常断点在 save: 方法处停止,但没有日志(log)/崩溃/错误

自定义 colored颜色 我的 UIActivityIndi​​catorView

检测 UITableView 滚动

创建 NSTextField标签的示例代码?

NSString 中子字符串的出现次数?

如何在 Xcode 7 中启用_BITCODE?

iPhone如何在打字时获取UITextField的文本?

如何更新 Core Data 中的现有对象?

判断 UIViewController 是否即将从导航堆栈中弹出?

UITableViewCell 选中行的文字 colored颜色 变化

如何使用图像和标签制作自定义 UIBarButtonItem?