키보드가 나타나거나 사라질 때 View 크기 조절 방법

회원가입 등 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;
}

생각보다 간단하죠? 테스트한 프로젝트도 함께 첨부합니다. 도움이 되셨으면 합니다.


Comments (2)

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.