UITableView в iOS 7 не прокручивается, чтобы исправить местоположение при редактировании UITextView в ячейке

У меня есть табличный вид со статическими ячейками. Одна ячейка содержит UITextView, а heightForRowAtIndexPath: вычисляется динамически, так что ячейка всегда достаточно высока, чтобы разместить текст (эта часть заняла определенную работу под iOS 7, фактически, поскольку уже невозможно просто запросить textView для его contentSize).

Когда я нажимаю в текстовом виде, чтобы начать редактирование, клавиатура анимируется на месте, контентные наборы в таблицеView автоматически настраиваются для учета этого (т.е. нижняя вставка 216 пикселей для ориентации на портфолио iPhone), курсор/карет становится видимый, а затем представление таблицы прокручивается в другое место. В итоге он выглядит как отскок.

Здесь видео этого в симуляторе: https://www.dropbox.com/s/htdbb0t7985u6n4/textview-bounce.mov

Обратите внимание: на секунду каретка находится чуть выше клавиатуры. Я регистрировал табличный вид contentOffset, и я вижу, что он прокручивает до хорошего значения, а затем внезапно "поворачивается" и прокручивает назад.

Как ни странно, если я включу медленную анимацию в симуляторе, проблема исчезнет; разворот contentOffset не происходит, и все работает так, как я ожидаю (т.е. поведение iOS 6).

Здесь видео с медленной анимацией: https://www.dropbox.com/s/nhn7vspx86t4exb/textview-nobounce.mov

Замечания по внедрению:

  • Текстовый вид является розовым и имеет ограничения AutoLayout, которые удерживают его прикрепленным к ячейке на расстоянии 0 (кроме левой стороны, которая составляет 10pts).
  • Я использую boundingRectWithSize: для вычисления высоты представления таблицы, настройки для lineFragmentPadding и любых верхних/нижних вложений. Кажется, работает.
  • Я установил, что textView не прокручивается, но не заметил ничего другого, когда scrollEnabled == YES
  • Это контроллер табличного представления и automaticallyAdjustsScrollViewInsets == YES

Ответ 1

Попробуйте настроить рамку UITableView при появлении клавиатуры. Вызовите [self attachKeyboardHelper] в viewWillAppear и [self detachKeyboardHelper] в viewWillDisappear.

- (void)attachKeyboardHelper{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillAppear:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}

- (void)detachKeyboardHelper{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)keyboardWillAppear:(NSNotification *)notification{
    NSDictionary* userInfo = [notification userInfo];

    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardEndFrame;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];

    // Animate up or down
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];

    CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
    if(self.view==self.tableView){
        CGRect newTableFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.view.bounds.size.height-keyboardFrame.size.height);
        self.tableView.frame = newTableFrame;
    }else{
        CGRect newTableFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.view.bounds.size.height-self.tableView.frame.origin.y-keyboardFrame.size.height);
        self.tableView.frame = newTableFrame;
    }

    [UIView commitAnimations];
}

- (void)keyboardWillHide:(NSNotification *)notification{
    NSDictionary* userInfo = [notification userInfo];

    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardEndFrame;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];


    CGRect newTableFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.view.superview.bounds.size.height-self.tableView.frame.origin.y);
    self.tableView.frame = newTableFrame;
    if(newTableFrame.size.height>self.tableView.contentSize.height-self.tableView.contentOffset.y){
        float newOffset=MAX(self.tableView.contentSize.height-newTableFrame.size.height, 0);
        [self.tableView setContentOffset:CGPointMake(0, newOffset) animated:YES];
    }

}