こんにちは、JAGA(ja_gaimopotato)です。
iOSのアプリを開発していて、テキスト入力のイベントの各種タイミングを知ったりキーボードのサイズを取得して、あれこれするということは、iOSアプリを作りはじめてすぐに気になったことでした。
色々と失敗しては、メモをして、ということを繰り返しながら知識を貯めているのですが、キーボードのサイズを取得する時に少しミスとしていたことがありました。
キーボード関連の通知を監視する
UITextViewのキーボードの表示、非表示の通知を受ける場合は、UIWindowで定義されているUIKeyboard関連の通知キーを関しすることで実装できます。
// キーボードの表示が始まる前
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];
// キーボードの表示が終わったあと
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil];
// キーボードが非表示になる前
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:nil];
// キーボードが非表示なったあと
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification object:nil];
// キーボードのサイズが変化するとき
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboarDidChangeFrame:)
name:UIKeyboardDidChangeFrameNotification object:nil];
で通知を監視します。
それぞれの通知ごとに呼ばれるメソッドを設定してキーボードの状態によってViewのサイズを変化させていくことなどに対応できます。
一括登録 & 解除する
実際には、これらの通知を一括登録するメソッドでも作っておいて、テキストの編集開始時に監視します。
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{
[self registerForKeyboardNotifications];
return YES;
}
で、テキストの編集が終わったら監視も終了する方が良いので、一括で解除するメソッドを設定します。
- (void)removeAllKeyboardNotifications{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidChangeFrameNotification object:nil];
}
タイミングに注意しよう
これを呼ぶタイミングは、編集が終わったあとが良いのですが以下のように
- (void)textViewDidEndEditing:(UITextView *)textView{
[self removeForKeyboardNotifications];
}
としてしまうと、UIKeyboardDidHideNotificationが得られないまま解除してしまいます。
ですので、UIKeyboardDidHideNotificationの通知を受けて呼ばれるメソッド内で通知を解除しなければなりません。
この例で言えば以下のようにします。
- (void)keyboardDidHide:(NSNotification *)notification{
[self removeAllKeyboardNotifications];
}
とすることで、キーボードの表示から非表示までの一連の動きを追うことができます。
ぼくが書いたコードではこのタイミングを間違っていたことで、keyboardDidHide:
が呼ばれない状態になっていたのです。
UIKeyboardDidChangeFrameNotificationで無理やりサイズを取得して解決するという何とも無駄な労力をかけていました。
反省です。