入力時にキーボードで隠れないように UITextField を UIToolbar に配置する方法

iPhone 画面下のツールバーにテキストボックスとボタンを配置して、コメント投稿バーみたいなやつを作ってみた。

f:id:griefworker:20121109060247p:plain

Storyboard からはツールバーにテキストボックスを直接配置できないけど、テキストボックスを UIBarButtonItem でくるんでツールバーに追加するようなコードを書くと配置できる。

ただ最初、NavigationController のツールバーにテキストボックスを配置したんだけど、文字を入力するときツールバーがキーボードの下に隠れてしまった。

そこで、新たにツールバーを配置して、そのなかにテキストボックスを配置し、キーボードが表示されたらツールバーの位置を変更するようにしている。もちろん、キーボードが閉じたら元の位置に戻す。

サンプルコードの抜粋は次の通り。

@interface DetailViewController () 

...

// ツールバー上に配置するボタンとテキストボックス
@property (nonatomic, strong) UIBarButtonItem *postButton;
@property (nonatomic, strong) UITextField *commentTextField;

...

@end

@implementation DetailViewController

// commentToolbar は Storyboard で配置
@synthesize commentToolbar = _commentToolbar;
@synthesize commentTextField = _commentTextField;
@synthesize postButton = _postButton;

...

- (void)viewDidLoad
{
    [super viewDidLoad];
  
    // ツールバーにテキストボックスとボタンを配置
    NSMutableArray *toolbarItems = [[NSMutableArray alloc] init];
    self.commentTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 240, 28)];
    self.commentTextField.delegate = self;
    [self.commentTextField setBorderStyle:UITextBorderStyleRoundedRect];
    UIBarButtonItem *commentItem = [[UIBarButtonItem alloc] initWithCustomView:self.commentTextField];
    [toolbarItems addObject:commentItem];
    self.postButton = [[UIBarButtonItem alloc] initWithTitle:@"Send"
                                                       style:UIBarButtonItemStyleBordered
                                                      target:nil
                                                      action:@selector(postNewComment:)];
    [toolbarItems addObject:self.postButton];
    [self.commentToolbar setItems:toolbarItems];
}

...

// キーボードが表示されたときの処理
- (void)keyboardWillShow:(NSNotification*)aNotification
{
    //キーボードの CGRect を取得
    CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardRect = [[self.view superview] convertRect:keyboardRect fromView:nil];
    
    //キーボードの animationDuration を取得
    NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    
    //メインビューの高さをキーボードの高さぶん引く
    CGRect frame = self.view.frame;
    frame.size.height -= keyboardRect.size.height;
    
    //キーボードアニメーションと同じ間隔でメインビューの高さをアニメーションしつつ変更する。
    [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
    [UIView setAnimationDuration:animationDuration];
    self.view.frame = frame;
    [UIView commitAnimations];
}

// キーボードが非表示になったときの処理
- (void)keyboardWillHide:(NSNotification*)aNotification
{
    //キーボードの CGRect を取得
    CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardRect = [[self.view superview] convertRect:keyboardRect fromView:nil];
    
    //キーボードの animationDuration を取得
    NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    //メインビューの高さをキーボードの高さぶん足す(=元の高さに戻す)    
    CGRect frame = self.view.frame;
    frame.size.height += keyboardRect.size.height;

    //キーボードアニメーションと同じ間隔でメインビューの高さをアニメーションしつつ変更する。    
    [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
    [UIView setAnimationDuration:animationDuration];
    self.view.frame = frame;
    [UIView commitAnimations];
}

- (void)viewWillAppear:(BOOL)animated
{
    // キーボード表示・非表示の通知を受け取ってツールバーの位置を調節する
    NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
    [defaultCenter addObserver:self
                      selector:@selector(keyboardWillShow:)
                          name:UIKeyboardWillShowNotification
                        object:self.view.window];
    [defaultCenter addObserver:self
                      selector:@selector(keyboardWillHide:)
                          name:UIKeyboardWillHideNotification
                        object:self.view.window];
}

- (void)viewWillDisappear:(BOOL)animated
{
    // 通知の受け取りを解除する
    NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
    [defaultCenter removeObserver:self
                             name:UIKeyboardWillShowNotification
                           object:nil];
    [defaultCenter removeObserver:self
                             name:UIKeyboardWillHideNotification
                           object:nil];
}

@end