Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

UITableView上で、キーボードを閉じる処理

More than 5 years have passed since last update.

はじめに

キーボードを閉じる処理は、UIView上だとUITapGestureRecognizerで閉じる処理を追加すれば済みます。
しかし、UITableViewでは、
本来のタップイベントが殺される為、そのままでは弊害があります。

解決手段を2つ、紹介します。

手段1:iOS7以降の標準機能を用いる

iOS7より、UIScrollViewkeyboardDismissModeプロパティが追加されました。
keyboardDismissModeを設定するだけで事足ります。

sample
// 上下のスワイプで、キーボードを閉じる
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;

// 指でキーボードを下方に引っ込めるジェスチャーを追加
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

ストーリーボードのkeyboardの項目から設定することも可能です。

UIScrollViewのプロパティなので、継承クラスのUITableViewでも利用できます。

手段2:タップジェスチャーを制御する

手段1では、キーボードを閉じる動作はスワイプのみで、タップ動作はありません。
加えて、Viewのタッチイベントも有効なので、
「キーボード入力中なのに誤って画面をタップしてしまう」など、使い勝手の悪いケースが出てきます。

そこで、なんとかタップジェスチャーを使えるようにします。
以下、目的別にコード分けて記述します。

タップでキーボードを閉じる

SampleViewController.m
-(void)viewDidAppear:(BOOL)animated
    // ジェスチャー追加:画面タップでキーボードを閉じる
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard)];
    [self.view addGestureRecognizer:tapGesture];
    // 後述のイベント切り分け用
    tapGesture.delegate = self;
}

// キーボードを閉じる
-(void)closeKeyboard
{
    [[self view] endEditing:YES];
}

しかし、冒頭で述べた様に、
元からタップイベントが存在するUITableViewなどは、ジェスチャーに割り込まれ、元のタップイベントが発生しなくなります。

タップジェスチャーとViewタップイベントの切り分け

Viewのタップイベントが殺されない様
・キーボード表示時は、タップジェスチャー
・キーボード非表示時は、View本来のタップイベント
それぞれが処理されるように切り分けを行います。

SampleViewController.h
// UIGestureRecognizerDelegateプロトコルの宣言
@interface SampleViewController : UITableViewController <UIGestureRecognizerDelegate>

SampleViewController.m
// タップジェスチャーの実行可否
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    // キーボード表示中のみ、タップジェスチャーを実行する
    // 表示中でないなら、SubViewにイベントを移譲
    // (keyboardShowingは仮のフラグです)
    if (keyboardShowing) {
        return YES;
    } else {
        return NO;
    }
}

gestureRecognizer:shouldReceiveTouch:は、
戻り値にNOを返す事で、ジェスチャー処理をキャンセルできます。
その場合、View(ジェスチャーの下層レイヤ)に、ジェスチャーイベントが移ります。

キーボード表示有無フラグの管理

タップイベントの切り分けを、キーボード表示有無で判断したいのですが、
キーボード表示状態を知るフラグが見当たりません。

仕方ないので、キーボード表示有無フラグを自前で用意します。

SampleViewController.m
@implementation SampleViewController {
    BOOL keyboardShowing;   // キーボード表示有無フラグ
}

// 画面表示後処理
-(void)viewDidAppear:(BOOL)animated
{
    // 通知センターの設定
    NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
    // 通知センターにキーボード表示処理開始を通知
    [notification addObserver:self
                     selector:@selector(keyboardWillShow)
                         name:UIKeyboardWillShowNotification
                       object:nil];
    // 通知センターにキーボード非表示処理終了を通知
    [notification addObserver:self
                     selector:@selector(keyboardDidHide)
                         name:UIKeyboardDidHideNotification
                       object:nil];
}

// 画面非表示後処理
-(void)viewDidDisappear:(BOOL)animated
{
    // 通知センターの解除(解除必須、忘れないこと)
    NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
    [notification removeObserver:self];
}

// イベント:キーボード表示開始
-(void)keyboardWillShow
{
    keyboardShowing = YES;
}

// イベント:キーボード表示終了
-(void)keyboardDidHide
{
    keyboardShowing = NO;
}

以上、
これでキーボード表示中はkeyboardShowingがYESになり、
タップジェスチャーは、キーボード表示中のみ有効になります。

最後に

手段2はタップ以外のジェスチャーでも可能です。
また、手段1・手段2は両立も可能です。

参考

[iOS 7] UIScrollView キーボードの扱い方が変わりました!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away