Как проверить, закрывает ли клавиатура UITextField в UITableView?

Как проверить, закрывает ли клавиатура первого ответчика внутри UIScrollView который может быть или не быть UITableView? Обратите внимание, что UIScrollView не обязательно будет охватывать весь viewController view и может содержаться в модальном представлении (UIModalPresentationFormSheet).

Я использую этот модифицированный код из справочной документации Apple и примера, но CGRectContainsPoint вернет false, даже если клавиатура явно покрывает первого ответчика. Очевидно, что я не использую convertRect:toView правильно.

Кроме того, код Apple не учитывает, что представление не является полноэкранным, поэтому настройка содержимого прокруткиViewInset на всю высоту клавиатуры не является отличным решением - она должна быть только вставкой для части клавиатуры первый ответчик.

- (void)keyboardWasShown:(NSNotification*)aNotification

{
 // self.scrollView can be a tableView or not. need to handle both
 UIView *firstResponderView = [self.scrollView findFirstResponder];
 if (!firstResponderView)
 return;

 NSDictionary* info = [aNotification userInfo];
 CGRect rect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

 // convertRect:toView? convertRect:fromView? Always confusing
 CGRect kbRect = [self.scrollView convertRect:rect toView:nil];
 CGRect viewRect = [self.scrollView convertRect:firstResponderView.bounds toView:nil];

 // doesn't work. convertRect misuse is certainly to blame 
 if (!CGRectContainsPoint(kbRect, firstResponderView.frame.origin))
 return;

 // Only inset to the portion which the keyboard covers?
 UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbRect.size.height, 0.0);
 self.scrollView.contentInset = contentInsets;
 self.scrollView.scrollIndicatorInsets = contentInsets;
}
1 ответ

Без дальнейшего тестирования или глубокого изучения логики эта строка кажется странной:

CGRect kbRect = [self.scrollView convertRect:rect toView:nil];

Прямоугольник клавиатуры (который включен в уведомление) находится в координатах окна, и вы, вероятно, захотите преобразовать его в систему координат прокрутки. [viewA convertRect:rect toView:viewB] преобразует rect из viewA системы координат в систему координат viewB, поэтому вы фактически делаете противоположное тому, что вы должны делать (как вы подозревали).

Обычно я делаю следующее:

- (void)keyboardWillShow:(NSNotification *)aNotification
{
 NSDictionary *info = [aNotification userInfo];
 CGRect kbRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
 kbRect = [self.view.window convertRect:kbRect toView:self.view]; // convert to local coordinate system, otherwise it is in window coordinates and does not consider interface orientation
 _keyboardSize = kbRect.size; // store for later use

 [UIView animateWithDuration:0.25 animations:^{
 UIEdgeInsets insets = UIEdgeInsetsMake(0.0f, 0.0f, MAX(0.0f, CGRectGetMaxY(_tableView.frame) - CGRectGetMinY(kbRect)), 0.0f); // NB: _tableView is a direct subview of self.view, thus _tableView.frame and kbRect are in the same coordinate system
 _tableView.contentInset = insets;
 _tableView.scrollIndicatorInsets = insets;
 [self scrollToActiveTextField]; // here I adapt the content offset to ensure that the active text field is fully visible
 }];
}

licensed under cc by-sa 3.0 with attribution.