今回の目的
ViewControllerのライフサイクルが存在しないUICollectionViewCellにて、
キーボードが現れた時に画面を良い感じにスクロールさせる。
ViewControllerのライフサイクルを活用する場合は下記記事をご参照下さい。
(とても参考になります)
UIScrollVIewの上でも、キーボードが現れたときにいい感じにスクロールする
UICollectionViewCellはUIViewControllerを継承していないので、
UIViewControllerのライフサイクルが利用できないので、
通知の登録、解除のタイミングがありません。
実装の方針
UITextFieldDelegateの下記デリゲートメソッドを利用して、
最新の押下されたTextFieldか判定する。
///テキストフィールドを編集する直前に呼び出される
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
return YES;
}
///テキストフィールドの編集が終了する直後に呼び出される
- (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason{
//行いたい処理を記載する
}
ロジック
今回のパターンで想定としない処理パターンが1点あります。
Aテキストフィールドを押下後にキーボードを下げずに、
Bテキストフィールドを押下した場合です。
このような処理をされた場合、内部的にはデリゲートメソッドの呼び出しは
A:編集直前
B:編集直前
A:編集終了直後 と呼び出されます。
仮に編集直後にスクロールを0,0にして元に戻すとしていたら、
Bが適切なスクロール位置に設定されません。
なので、クラスにインスタンス変数を追加して、
**「現在押下されているTextField」**を保存して参照可能にしたいと思います。
///テキストフィールドの編集が終了する直後に呼び出される
- (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason{
//行いたい処理を記載する
if([textField isEqual self.selectedTextField]){
[self.scrollView setContentOffset:CGPointMake(0, 0)];
}
}
解説
A:編集直前
B:編集直前
A:編集終了直後
先ほど説明した手順で問題があるのがA編集終了直後でBを編集中なのに、
スクロールを(0,0)に戻している点です。
なので、終了直後に引数で渡されているTextFieldは編集中のTextFieldか、
インスタンス変数と比較してチェックしています。
コード全文
# import "CustomCollectionViewCell.h"
@interface CustomCollectionViewCell()<UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITextField *topTextFiled;
@property (weak, nonatomic) IBOutlet UITextField *bottomTextField;
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
///現在フォーカスされているTextField
@property (nonatomic) UITextField *selectedTextField;
@end
@implementation CustomCollectionViewCell
- (void)awakeFromNib {
[super awakeFromNib];
self.topTextFiled.delegate = self;
self.bottomTextField.delegate = self;
}
///テキストフィールドを編集する直前に呼び出される
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
self.selectedTextField = textField;
switch (textField.tag) {
case 0:
[self.scrollView setContentOffset:CGPointMake(0, 0)];
break;
case 1:
[self.scrollView setContentOffset:CGPointMake(0, textField.frame.origin.y - 50)];
break;
default:
break;
}
return YES;
}
///テキストフィールドの編集が終了する直後に呼び出される
- (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason{
if([textField isEqual:self.selectedTextField]){
[self.scrollView setContentOffset:CGPointMake(0, 0)];
}
}
@end
補足
参照記事などではキーボードの高さ分、スクロール位置を調整しておりますが、
本クラス内では通知で受け取れるのですが、
解除するタイミングが無いのでキーボードの取得は難しそうですね。
親CollectionViewで通知解除とかいちいちやれば出来るかもです。
改良したらまた投稿します。
途中で書いた [self.scrollView setContentOffset:CGPointMake(0, textField.frame.origin.y - 50)];
ですが、一番上から50pt開ければ入力しやすいだろう、
という事で50に設定しております。
調査を追加し、記事を追加しました。
UICollectionViewCell(カスタムセル)で通知を受け取り、キーボードが出た時に良い感じにスクロールさせて戻る。