Unscrollable UITextView в UITableViewCell - Как определить координату курсора y - PullRequest
0 голосов
/ 07 марта 2011

Я использую UITextView внутри ячейки UITableView. У меня отключена прокрутка для UITextView. Когда пользователь печатает, у меня есть логика для автоматического увеличения как ячейки UITextView, так и ячейки UITableView. У меня также есть логика, чтобы автоматически прокручивать UITableView и держать вновь напечатанный текст видимым. Я делаю это, вызывая [tableView scrollRectToVisible: animated:]. Все это работает нормально, если курсор находится в самом конце текста, поскольку я просто прокручиваю до конца (tableView.contentSize.height).

Проблема возникает, когда пользователь решает расположить курсор в другом месте текста (скажем, в середине своего блока) и снова начинает печатать. На данный момент я больше не могу держать вновь введенный текст в поле зрения, потому что я не могу определить, по какой координате у находится курсор.

Любая помощь будет принята с благодарностью!

Ответы [ 3 ]

1 голос
/ 20 мая 2011

ОК, я наконец-то реализовал это, и там стало намного проще, вам не нужно использовать contentOffset, как я уже говорил, он работает, но имеет некоторые неожиданные проблемы. Хитрость заключается в использовании вспомогательного UITextView для вычисления высоты текста над курсором.

Вот идея (я проверял и работает):

  • Создать вспомогательное UITextView (_auxTextView)

  • Реализация делегата textViewDidChange для основного представления текста.

Контроллер табличного представления должен реализовать cellDidChange, прокручивая табличное представление, используя scrollRectToVisible с заданным смещением. Точные вычисления зависят от случая, но важная вещь здесь вызывает beginUpdate и endUpdate, чтобы принудительно обновить высоту строки, которая должна быть основана на свойстве rowHeight.

Вот часть кода (извините, я не могу опубликовать реальный код, потому что он находится внутри большого контекста).

    -(void)textViewDidChange:(UITextView *)textView {
      if(_prevHeight != self.textHeight) {
        _prevHeight = self.textHeight;
        NSRange range;
        range.location = 0;
        range.length = textView.selectedRange.location;
        NSString *str = [_textView.text substringWithRange:range];
        _auxTextView.text = str;
        [delegate cellDidChange:self offset:_auxTextView.contentSize.height];
      }
    }

   -(CGFloat)rowHeight {
      return self.textHeight + somePadding;
    }

   -(CGFloat)textHeight {
     return fmaxf(_textView.contentSize.height, someMinimumHeight);
   }
0 голосов
/ 19 мая 2011

На самом деле есть более простой способ сделать это:)

Просто добавьте скрытый UITextView и отразите все изменения, сделанные в основном текстовом представлении в скрытом. Представление скрытого текста должно иметь фиксированную высоту, поэтому оно будет прокручиваться автоматически, изменяя свойство contentOffset. И contentOffset - это именно то, что вам нужно для вычисления вертикальной позиции курсора.

Goog удачи!

0 голосов
/ 08 марта 2011

Мне удалось решить эту проблему (по крайней мере, в большинстве случаев), но это может быть сложно. Получить координату у не так сложно. Подавление ложных сообщений прокрутки, которые система запускает на вашем столе, может быть.

Подход, который я выбрал, выглядит следующим образом:

  • в делегате для вашего UITextView реализовать textViewDidChangeSelection:
  • получить текст из textView и selectedRange
  • вам может понадобиться проверить, что выбранный диапазон не> длины текста (иногда это может быть; если вы считаете, что это невозможно, вы можете получить странные сбои ... я сделал)
  • обрезать строку, чтобы вы получили строку от начала до точки выбора
  • вычисляет высоту UITextView для строки этой длины. Используйте что-то вроде:

    textHeight = [workingString sizeWithFont: [self screenFont] constrainedToSize: CGSizeMake ([self editWidth] -16.0, CGFLOAT_MAX)]. Height;

  • -16.0 важно для компенсации границы по умолчанию. У меня был хороший успех с 16.0, но это не задокументировано. Может быть, есть лучший способ выяснить компенсацию, но я не сработал.

  • В этот момент я вручную прокручиваю tableView. Это подкласс UIScrollView, поэтому отвечает на setContentOffset: однако, чтобы все работало гладко, я подклассифицировал UITableView и иногда заставлял его игнорировать contentOffset: и contentOffset: animated: messages. Система генерирует их, и иногда это происходит, когда вы не хотите их. (Это то, что я имею в виду под «хитрым»).

Там может быть гораздо более простой способ достичь этого. Я надеюсь, что это так. И если это так, то кто-то это публикует.

Вот немного (немного некрасивого) кода из моего приложения (все еще в работе). Он использует некоторые другие классы / категории из моего приложения, но, надеюсь, вы сможете с готовностью следить за тем, что происходит. Это может не совсем соответствовать вашей проблеме, но, надеюсь, это будет полезно.

- (void) textViewDidChangeSelection: (UITextView *)textView;
{
    if (!checkSelectionVisible) return; // bail most of the time
    checkSelectionVisible = NO; // this is a one off

    EditController* theEditController = [self editController];
    ParagraftTableView* theTableView = (ParagraftTableView*)[theEditController tableView];

    ParagraphCell* currentCell = (ParagraphCell*) [theTableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:[self paragraphNumber] inSection:0]];

    CGPoint cellOrigin = currentCell.origin;
    CGPoint contentOffset = [theTableView contentOffset];
    NSRange selectedRange = [textView selectedRange];
    NSString* text = [textView text];
    if (selectedRange.location > [text length])
    {
        selectedRange.location = 0; // of out of bounds set to start
        NSLog(@"In textViewDidChangeSelection - selection out of bounds. Setting to start of paragraph.");
    }

    CGFloat textHeight = [[Formats shared] heightForText: [text substringToIndex: selectedRange.location]]; 

    if ((cellOrigin.y + textHeight) > ([theTableView height]+ [theTableView contentOffset].y))
    {
        NSLog(@"Selection point is off screen. Scroll into view.");

        CGFloat txHeight = [[[Formats shared] screenFont] pointSize];
        CGFloat newOffset = cellOrigin.y + textHeight - ([theTableView height] - 3*txHeight);
        contentOffset.y = newOffset;

        [theTableView setContentOffset:contentOffset];
    }
}
...