#はじめに
キーボードを閉じる処理は、UIView上だとUITapGestureRecognizer
で閉じる処理を追加すれば済みます。
しかし、UITableViewでは、
本来のタップイベントが殺される為、そのままでは弊害があります。
解決手段を2つ、紹介します。
#手段1:iOS7以降の標準機能を用いる
iOS7より、UIScrollView
にkeyboardDismissMode
プロパティが追加されました。
keyboardDismissMode
を設定するだけで事足ります。
// 上下のスワイプで、キーボードを閉じる
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
// 指でキーボードを下方に引っ込めるジェスチャーを追加
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
ストーリーボードのkeyboard
の項目から設定することも可能です。
UIScrollViewのプロパティなので、継承クラスのUITableViewでも利用できます。
#手段2:タップジェスチャーを制御する
手段1では、キーボードを閉じる動作はスワイプのみで、タップ動作はありません。
加えて、Viewのタッチイベントも有効なので、
「キーボード入力中なのに誤って画面をタップしてしまう」など、使い勝手の悪いケースが出てきます。
そこで、なんとかタップジェスチャーを使えるようにします。
以下、目的別にコード分けて記述します。
###タップでキーボードを閉じる
-(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本来のタップイベント
それぞれが処理されるように切り分けを行います。
// UIGestureRecognizerDelegateプロトコルの宣言
@interface SampleViewController : UITableViewController <UIGestureRecognizerDelegate>
// タップジェスチャーの実行可否
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
// キーボード表示中のみ、タップジェスチャーを実行する
// 表示中でないなら、SubViewにイベントを移譲
// (keyboardShowingは仮のフラグです)
if (keyboardShowing) {
return YES;
} else {
return NO;
}
}
gestureRecognizer:shouldReceiveTouch:
は、
戻り値にNOを返す事で、ジェスチャー処理をキャンセルできます。
その場合、View(ジェスチャーの下層レイヤ)に、ジェスチャーイベントが移ります。
###キーボード表示有無フラグの管理
タップイベントの切り分けを、キーボード表示有無で判断したいのですが、
キーボード表示状態を知るフラグが見当たりません。
仕方ないので、キーボード表示有無フラグを自前で用意します。
@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は両立も可能です。