UITextView в UITableViewCell плавного автоматического изменения размера показывает и скрывает клавиатуру на iPad, но работает на iPhone - PullRequest
17 голосов
/ 25 октября 2010

Я реализовал пользовательский UITableViewCell, который включает в себя UITextView, который автоматически изменяет размеры в зависимости от типа пользователя, аналогично полю «Примечания» в приложении «Контакты». Он нормально работает на моем iPhone, но когда я тестирую его на iPad, у меня возникает очень странное поведение: когда вы добираетесь до конца строки, клавиатура прячется на миллисекунду и затем сразу же снова показывает себя. Я бы списал это как причудливую ошибку, но на самом деле это приводит к некоторой потере данных, поскольку, если вы печатаете, она теряет один или два символа. Вот мой код:

Код

// returns the proper height/size for the UITextView based on the string it contains.
// If no string, it assumes a space so that it will always have one line.
- (CGSize)textViewSize:(UITextView*)textView {
     float fudgeFactor = 16.0;
     CGSize tallerSize = CGSizeMake(textView.frame.size.width-fudgeFactor, kMaxFieldHeight);
     NSString *testString = @" ";
     if ([textView.text length] > 0) {
          testString = textView.text;
     }
     CGSize stringSize = [testString sizeWithFont:textView.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
     return stringSize;
}

// based on the proper text view size, sets the UITextView's frame
- (void) setTextViewSize:(UITextView*)textView {
     CGSize stringSize = [self textViewSize:textView];
     if (stringSize.height != textView.frame.size.height) {
          [textView setFrame:CGRectMake(textView.frame.origin.x,
                                        textView.frame.origin.y,
                                        textView.frame.size.width,
                                        stringSize.height+10)];  // +10 to allow for the space above the text itself 
     }
}

// as per: https://stackoverflow.com/questions/3749746/uitextview-in-a-uitableviewcell-smooth-auto-resize
- (void)textViewDidChange:(UITextView *)textView {

     [self setTextViewSize:textView]; // set proper text view size
     UIView *contentView = textView.superview;
     // (1) the padding above and below the UITextView should each be 6px, so UITextView's
     // height + 12 should equal the height of the UITableViewCell
     // (2) if they are not equal, then update the height of the UITableViewCell
     if ((textView.frame.size.height + 12.0f) != contentView.frame.size.height) {
         [myTableView beginUpdates];
         [myTableView endUpdates];

         [contentView setFrame:CGRectMake(0,
                                          0,
                                          contentView.frame.size.width,
                                          (textView.frame.size.height+12.0f))];
     }
}

- (CGFloat)tableView:(UITableView  *)tableView heightForRowAtIndexPath:(NSIndexPath  *)indexPath {
     int height;
     UITextView *textView = myTextView;
     [self setTextViewSize:textView];
     height = textView.frame.size.height + 12;
     if (height < 44) { // minimum height of 44
          height = 44;
          [textView setFrame:CGRectMake(textView.frame.origin.x,
                                        textView.frame.origin.y,
                                        textView.frame.size.width,
                                        44-12)];
      }
      return (CGFloat)height;
}

Проблемы

Итак, вот что происходит

  1. Этот код работает на 100% правильно на моем iPhone и в симуляторе iPhone. Когда я набираю текст, UITextView растет плавно, и UITableViewCell вместе с ним.
  2. Однако на симуляторе iPad он становится чокнутым. Он отлично работает, когда вы печатаете в первой строке, но когда вы добираетесь до конца строки, клавиатура исчезает, а затем сразу же появляется снова, так что если пользователь продолжает набирать текст, приложение пропускает один или два символа.
  3. Вот некоторые дополнительные заметки о странном поведении, которое я заметил, которые могут помочь объяснить это:
    • Кроме того, я обнаружил, что удаление строк [myTableView beginUpdates]; [myTableView endUpdates]; в функции textViewDidChange:(UITextView *)textView заставляет UITextView правильно расти, а также не отображает и не скрывает клавиатуру, но, к сожалению, тогда UITableViewCell не растет должным образом высота.
    • ОБНОВЛЕНИЕ: Следуя этим инструкциям , теперь я могу остановить странное движение текста; но клавиатура все еще прячется и показывает, что очень странно.

У кого-нибудь есть идеи, как заставить клавиатуру постоянно показывать, а не прятаться и показывать, когда вы доберетесь до конца строки на iPad?

P.S .: Я не заинтересован в использовании ThreeTwenty.

Ответы [ 2 ]

15 голосов
/ 30 октября 2010

Вы должны вернуть NO в:

 -(BOOL) textViewShouldEndEditing:(UITextView *)textView

, если хотите постоянно показывать клавиатуру.Вы должны обрабатывать случаи, клавиатура которых должна быть скрыта, возвращая YES этой функции делегата.

edit:

Я вырыл немного больше, когда [tableView endUpdates] вызываемый, он в основном делает 3 вещи:

  1. Отключает взаимодействие с пользователем на tableView
  2. Обновляет изменения ячеек
  3. Включает взаимодействие с пользователем на tableView

Разница между SDK (платформами) составляет [UIView setUserInteractionEnabled] метод.Поскольку UITableView не перезаписывает метод setUserInteractionEnabled , он вызывается из super (UIView).

iPhone, когда вызывается setUserInteractionEnabled , ищет личное поле _shouldResignFirstResponDisInIn1033 *, который возвращает NO по умолчанию, поэтому первый респондент не уходит в отставку (UITextView)

Но на iPad такой проверки AFAIK нет, поэтому он отказывается UITextView на шаг 1 , устанавливает фокус и делает его первым отвечающим на шаг 3

По сути, textViewShouldEndEditing, который позволяет вам сохранять фокус,в соответствии с SDK docs, ваша единственная опция - ATM.

Этот метод вызывается, когда текстовое представление запрашивает отставку статуса первого респондента.Это может произойти, когда пользователь пытается изменить фокус редактирования на другой элемент управления.Однако, прежде чем фокус действительно изменится, текстовое представление вызывает этот метод, чтобы дать вашему делегату возможность решить, следует ли ему это делать.

11 голосов
/ 30 января 2011

У меня была та же проблема с приложением для iPad, и я нашел другое решение, не рассчитав высоту самого текста.

Сначала создайте пользовательский UITableViewCell в IB с UITextField, помещенным в contentView ячейки. Важно установить для текстового представления scrollEnabled значение NO, а для autoresizingMask - FlexibleWidth и FlexibleHeight.


В ViewController реализуйте метод делегата текстового представления -textViewDidChanged: следующим образом, где textHeight является переменной экземпляра с типом CGFloat, а -tableViewNeedsToUpdateHeight является Пользовательский метод мы определим на следующем шаге.

- (void)textViewDidChange:(UITextView *)textView
{
    CGFloat newTextHeight = [textView contentSize].height;

    if (newTextHeight != textHeight)
    {
        textHeight = newTextHeight;
        [self tableViewNeedsToUpdateHeight];
    }
}

Метод -tableViewNeedsToUpdateHeight вызывает beginUpdates и endUpdates представления таблицы, поэтому само представление таблицы будет вызывать -tableView: heightForRowAtIndexPath: метод делегата.

- (void)tableViewNeedsToUpdateHeight
{
    BOOL animationsEnabled = [UIView areAnimationsEnabled];
    [UIView setAnimationsEnabled:NO];
    [table beginUpdates];
    [table endUpdates];
    [UIView setAnimationsEnabled:animationsEnabled];
}

В табличном представлении -tableView: heightForRowAtIndexPath: метод делегата нам нужно вычислить новую высоту для ячейки текстового представления на основе textHeight .

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

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    CGFloat heightForRow = 44.0;

    if ([indexPath row] == kRowWithTextViewEmbedded)
    {
        CGFloat tableViewHeight = [tableView bounds].size.height;
        heightForRow = tableViewHeight - ((kYourTableViewsNumberOfRows - 1) * heightForRow);

        if (heightForRow < textHeight) 
        {
            heightForRow = textHeight;
        }
    }

    return heightForRow;
}

Для лучшего взаимодействия с пользователем установите вкладки содержимого табличного представления для нижней части, например. 50,0.

Я протестировал его на iPad с iOS 4.2.1 и работает как положено.

Florian

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...