회원가입 등 UITableViewCell에 subView로 UITextField, UITextView 등이 존재하고,
이를 터치했을 경우 키보드가 나타날 때 입력해야 할 공간이 키보드에 덮혀버리는 문제가 생기는데요.
이 때 위 문제를 해결하기 위해 여러 방법을 생각할 수 있을 것입니다.
UITableView를 안쓰면 되잖어! 라고 생각하시는 분도 계실테고 다른 꼼수를 이용하여 구현하시는 분도 계실 것입니다. 제가 구현한 방법은 아래와 같습니다.
1. ViewController의 기본 메소드 중 viewWill(Did)Appear, viewWill(Did)Disappear에서 Keyboard Notification의 Observer를 생성/삭제 합니다. name은 UIKeyboardWill(Did)ShowNotification, UIKeyboardWill(Did)HideNotification 으로 정의된 키보드 Notification을 View가 그려지기 전에 Observer에 등록하고, View가 사라지기 전에 삭제하였습니다.
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appearKeyboard:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disappearKeyboard:) name:UIKeyboardDidHideNotification object:nil]; }
- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil]; }
2. 키보드 이벤트의 selector를 아래와 같이 정의합니다. 여기서 중요한 부분은 NSNotification에 정의된 userInfo 입니다. 키보드가 나타나는 이벤트의 duration, curve를 비롯하여 frame 정보가 이 userInfo에 정의되어 있습니다. 따라서 이 userInfo 값을 참조하여 키보드가 나타나거나 사라질 때 UITableView의 frame을 변경하고 선택한 row의 index 값을 참고하여 해당 indexPath로 scroll 해주는 것입니다.
- (void)appearKeyboard:(NSNotification *)noti { CGRect frame = {0.0f, 0.0f, 0.0f, 0.0f}; CGFloat animationDuration = 0.0f; [[noti.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&frame]; [[noti.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; _tableView.frame = CGRectMake(0.0f,0.0f,320.0f,416.0f-frame.size.height); [UIView animateWithDuration:animationDuration animations:^(void) { } completion:^(BOOL finished) { if (finished) { [_tableView scrollToRowAtIndexPath: [NSIndexPath indexPathForRow:_selectedRow inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; } }]; }
- (void)disappearKeyboard:(NSNotification *)noti { _tableView.frame = CGRectMake(0.0f,0.0f,320.0f,416.0f); }
3. UITextField의 delegate 메소드는 아래와 같이 구현하였는데 입력을 위해 UITextField를 터치했을 때 터치된 UITextField의 부모를 참조하여 해당 cell의 index 값을 임시로 저장하였고, “완료”를 눌렀을 때는 키보드를 숨기기 위해 resignTextField 메소드를 호출하였습니다.
- (void)textFieldDidBeginEditing:(UITextField *)textField { UITableViewCell *cell = (UITableViewCell *)[[textField superview] superview]; NSIndexPath *indexPath = [_tableView indexPathForCell:cell]; _selectedRow = indexPath.row; }
- (BOOL)textFieldShouldReturn:(UITextField *)textField { if ([textField isFirstResponder]) { [textField resignFirstResponder]; } return NO; }
생각보다 간단하죠? 테스트한 프로젝트도 함께 첨부합니다. 도움이 되셨으면 합니다.
2 comments
Hi there, just became aware of your weblog by way of Google, and identified that it is genuinely informative. I
Thanks.