Как сделать UITableViewCell с UITextView внутри, который динамически регулирует его высоту на основе UITextView? - PullRequest
42 голосов
/ 21 ноября 2010

Мне бы хотелось иметь табличное представление с поведением, аналогичным приложению iPhone для контактов от Apple: uitableviewcell с uitextview внутри, так что когда я пишу в uitextview, uitextview увеличивает свою высоту, и соответственно соответственно uitableviewcellдинамически регулирует свою высоту.Я искал по всей сети, находя только частичные решения и отсутствие примера кода!

, пожалуйста, помогите мне, я в отчаянии

Тони

Ответы [ 10 ]

37 голосов
/ 22 ноября 2010

Глядя на это, нужно быть несколько хитрым.Вам необходимо рассчитать высоту textView динамически и на основе высоты TextView, вам нужно вернуть высоту для ячейки.

Это очень просто и немного сложно ..

Это код, по которому вы можете вычислить размер строки ....

Сначала получите размер строки

NSString *label =  @"Sample String to get the Size for the textView Will definitely work ";
CGSize stringSize = [label sizeWithFont:[UIFont boldSystemFontOfSize:15]
                      constrainedToSize:CGSizeMake(320, 9999)
                          lineBreakMode:UILineBreakModeWordWrap];

over here ....
NSLog(@"%f",stringSize.height);

Во-вторых, динамически создайте текстовое представление в ячейке ... даваяstringSize.height

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    //if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    //}

    NSDictionary *d=(NSDictionary *)[self.menuArray objectAtIndex:indexPath.section];

    NSString *string = [d valueForKey:@"Description"];
    CGSize stringSize = [string sizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:UILineBreakModeWordWrap];

    UITextView *textV=[[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, stringSize.height+10)];
    textV.font = [UIFont systemFontOfSize:15.0];
    textV.text=string;
    textV.textColor=[UIColor blackColor];
    textV.editable=NO;
    [cell.contentView addSubview:textV];
    [textV release];

    return cell;
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath  {  

    NSDictionary *d=(NSDictionary *)[self.menuArray objectAtIndex:indexPath.section];
    NSString *label =  [d valueForKey:@"Description"];
    CGSize stringSize = [label sizeWithFont:[UIFont boldSystemFontOfSize:15]
                          constrainedToSize:CGSizeMake(320, 9999) 
                              lineBreakMode:UILineBreakModeWordWrap];

    return stringSize.height+25;

} 

После того, как мои пальцы сильно болели, ...... Я думаю, этого достаточно, код ... и, несомненно, поможет решить вашу проблему ..

Удачи

12 голосов
/ 25 ноября 2010

Создайте пользовательский UITableViewCell и добавьте свой UITextView в contentView ячейки.

В LayoutSubviews установите для textView.frame значение contentView.bounds ячейки (или создайте другой пользовательский макет).

Когда содержимое textView изменяется (обнаруживается через UITextViewDelegate), выполните две вещи:

1) вызов [tableView beginUpdates]; [tableView endUpdates]; Это заставит представление таблицы пересчитать высоту для всех ячеек (вызовет tableView:heightForRowAtIndexPath:). Если ваша ячейка является делегатом для textView, вам придется выяснить, как получить указатель на tableView, но есть несколько способов добиться этого. Или вы могли бы сделать делегатом ваш контроллер представления ...

2) когда для этой ячейки вызывается tableView:heightForRowAtIndexPath:, вернуть textView.contentSize.height. Вы можете получить свою ячейку отсюда, вызвав [tableView cellForRowAtIndexPath]; Или, если у вас есть только одна из этих ячеек, кешируйте указатель на нее в вашем viewController.

3 голосов
/ 23 октября 2014

Единственная проблема, которую я обнаружил с принятым ответом, заключалась в том, что мы выделяем UITextView каждый раз. Я обнаружил, что это вызвало проблемы с вводом в представление и немедленным обновлением текста, а также сохранением представления в качестве первого респондента. Когда я попытался перезагрузить ячейку с новой высотой, он попытался бы добавить новый textView.

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

1) В заголовочном файле определите переменную для высоты текста и textView:

UITextView * _textView;
NSInteger _textHeight;

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

2) Загрузите текстовое представление и добавьте его в нашу ячейку

_textView = [[UITextView alloc] init];
_textView.delegate = self;
_textView.returnKeyType = UIReturnKeyDone;
_textView.font = [UIFont fontWithName:@"Helvetica" size:16];

if (![_user metaStringForKey:bBioKey].length) {
    _textView.text = @"Placeholder text";
    _textView.textColor = [UIColor lightGrayColor];
}


- (UITableViewCell *)tableView:(UITableView *)tableView_ cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (indexPath == 0) { // Add logic to choose the correct cell

        if (_textView.superview != cell) {

            [cell addSubview:_textView];     

            _textView.keepTopInset.equal = KeepRequired(7);
            _textView.keepBottomInset.equal = KeepRequired(7);
            _textView.keepRightInset.equal = KeepRequired(10);
            _textView.keepLeftInset.equal = KeepRequired(70);
            }
        }
    }
}

Использование keeplayout позволило нам сохранить наше текстовое поле всегда на той же высоте, что и ячейка. Мы также только один раз добавляем наш UITextView.

3) Добавьте код для расчета высоты текста

- (NSInteger)getHeightOfBio: (NSString *)text {

    UILabel * gettingSizeLabel = [[UILabel alloc] init];
    gettingSizeLabel.font = [UIFont fontWithName:@"Helvetica" size:16];
    gettingSizeLabel.text = text;
    gettingSizeLabel.numberOfLines = 0;
    CGSize maximumLabelSize = CGSizeMake(240, 9999); // this width will be as per your requirement

    CGSize expectedSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

    return expectedSize.height;
}

Я пробовал много и нашел, что это работает лучше всего

4) Добавьте немного логики в высоту ячейки, чтобы использовать это:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (indexPath.row == 0) { // Set the height for our changing textView

        return 30 + [self getHeightOfBio:_textView.text];
    }

    return 44;
}

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

5) Обновляйте представление каждый раз, когда вводится символ, чтобы проверить, нужно ли нам увеличивать размер:

- (void)textViewDidChange:(UITextView *)textView {

    if ([self getHeightOfText:textView.text] != _textHeight) {

       _textHeight = [self getHeightOfText:textView.text];

       [self.tableView beginUpdates];
       [self.tableView endUpdates];
    }
}

В этом разделе мы получаем высоту текста каждый раз, когда пользователь печатает.

Тогда, хотя мы используем наше сохраненное значение и сравниваем текущее значение с сохраненным значением. Очевидно, что если они одинаковы, то нет смысла обновлять представление. Если они отличаются, мы обновляем значение и затем обновляем нашу таблицу.

Этот бит я нашел хороший ответ на stackOverflow, показывающий, как мы можем обновлять только высоты таблицы вместо самой ячейки. Зачем обновлять камеру, когда нам не нужно? Это означает, что как только это называется, высота ячейки обновляется, и она приятно увеличивается.

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

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

2 голосов
/ 04 декабря 2012

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

1 голос
/ 06 января 2015

Я редактирую ответ TomSwift, который является лучшим способом сделать это:

вот код моей ячейки (в быстром)

class CommentaireTextViewCell: UITableViewCell,UITextViewDelegate {

@IBOutlet weak var textViewCom: UITextView!
weak var parentTableView:UITableView?

@IBOutlet weak var constraintTextViewTopMargin: NSLayoutConstraint!
@IBOutlet weak var constraintTextViewHeight: NSLayoutConstraint!
@IBOutlet weak var constraintTextViewBottomMargin: NSLayoutConstraint!
override func awakeFromNib() {
    self.textViewCom.delegate = self;
}

func textViewDidChange(textView: UITextView) {
    self.parentTableView?.beginUpdates();
    self.parentTableView?.endUpdates();
}

func getHeight() -> CGFloat
{
    constraintTextViewHeight.constant = self.textViewCom.contentSize.height;
    // cell height = textview marge top+ textview height+ textView Marge bottom
    return constraintTextViewTopMargin.constant+constraintTextViewHeight.constant+constraintTextViewBottomMargin.constant+8
    // add 8 because it seems to have an inset inside the textView
}

override func setSelected(selected: Bool, animated: Bool) {
    self.textViewCom.becomeFirstResponder();
}
}

для объяснения, представление таблицы ячеек являетсяслабые свойства ячейки, поэтому я могу сказать ей обновить макет, когда пользователь вводит текст.Высота ячейки является суммой ее верхнего ограничения для contentView, его нижнего ограничения для contentView и textView.contantSize.height, которое также равно константе textView height

enter image description here

1 голос
/ 05 мая 2012

Наконец-то у меня все заработало.Основная проблема заключается в том, как получить правильную ширину ячейки contentView.Ширина в жестком коде работает не во всех случаях, поскольку она может варьироваться соответственно стилю простой / сгруппированной таблицы, добавленным аксессуарам или макету ландшафта / портрета.Единственный способ получить 100% правильную ширину - это запросить ее у объекта ячейки.Поэтому я создаю ячейку прямо в heightForRowAtIndexPath и сохраняю ее в кеше, затем эта ячейка будет возвращена методом cellForRowAtIndexPath.Другая проблема заключается в том, как заставить ячейку размещать свои подпредставления перед использованием.Это можно сделать, если мы временно добавим ячейку к tableView и обновим фрейм ячейки с шириной tabelView.После этого все подпредставления будут правильно размещены. Здесь - это то, как я это сделал в моей библиотеке TableKit .

0 голосов
/ 12 марта 2014

Попробуйте следующий код:

CGSize constraintSize;
constraintSize.height = MAXFLOAT;
constraintSize.width = yourTextView.frame.size.width;
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                      [UIFont fontWithName:@"yourFontName" size:yourFontSize], NSFontAttributeName,
                                      nil];

CGRect frame = [yourTextView.text boundingRectWithSize:constraintSize
                                  options:NSStringDrawingUsesLineFragmentOrigin
                               attributes:attributesDictionary
                                  context:nil];

CGSize stringSize = frame.size;//The string size can be set to the UITableViewCell
0 голосов
/ 06 декабря 2012

Ребята, это действительно классная вещь, но вы можете использовать tableview: didSelectRowForIndexPath: добавить UITextView в ячейку в качестве подпредставления, когда пользователь нажимает на нее, работает очень хорошо, так как вам нужно использовать только 1 UITextView, который вы можете использовать повторно и выиграть не мешайте столу получать прикосновения! Отпустите его, когда закончите.

подробности? просто спросите!

0 голосов
/ 25 ноября 2010

вы можете получить размер UITextView программно. В соответствии с размером установите высоту ячейки, используя следующий делегат

tableView:heightForRowAtIndexPath:
0 голосов
/ 21 ноября 2010

Вам необходимо вернуть правильную высоту в методе делегата heightForRowAtIndexPath.

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