Динамічно змінювати розмір UITableViewCell на основі текстового введення

Я намагаюсь динамічно змінити розмір деякого UITableViewCell на основі висоти UITextView , що містяться в них. Там є багато рішень для цього, зберігаючи вказівник на UITextView і отримуючи його розмір в heightForRowAtIndexPath , проте, коли вся таблиця створюється динамічно з невідомою кількістю рядків та невідома їх кількість рядків містить UITextView , це просто неможливо. Було б легко, якщо б я міг викликати цю клітину під час heightForRowAtIndexPath , але це викликає нескінченний цикл і аварійне завершення роботи, оскільки цей метод викликається до створення будь-якої комірки. Будь-які інші рішення?

Я використовую підклас UITableViewCell для моєї комірки, як це:

- (void)initalizeInputView {
   //Initialization code
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    self.textView = [[UITextView alloc] initWithFrame:CGRectZero];
    self.textView.autocorrectionType = UITextAutocorrectionTypeDefault;
    self.textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
    self.textView.textAlignment = NSTextAlignmentRight;
    self.textView.textColor = [UIColor lightBlueColor];
    self.textView.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:17];
    self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    self.textView.keyboardType = UIKeyboardTypeDefault;
    [self addSubview:self.textView];

    self.textView.delegate = self;
}

- (BOOL)resignFirstResponder {
    if (_delegate && [_delegate respondsToSelector:@selector(tableViewCell:didEndEditingWithLongString:)]) {
        [_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
    }
    return [super resignFirstResponder];
}

- (void)setKeyboardType:(UIKeyboardType)keyboardType
{
    self.textView.keyboardType = keyboardType;
}

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self initalizeInputView];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self initalizeInputView];
    }
    return self;
}

- (void)setSelected:(BOOL)selected {
    [super setSelected:selected];
    if (selected) {
        [self.textView becomeFirstResponder];
    }
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
    if (selected) {
        [self.textView becomeFirstResponder];
    }
}

- (void)setStringValue:(NSString *)value {
    self.textView.text = value;
}

- (NSString *)stringValue {
    return self.textView.text;
}

- (void)textViewDidBeginEditing:(UITextView *)textView
{
   //For keyboard scroll
    UITableView *tableView = (UITableView *)self.superview;
    AppSetupViewController *parent = (AppSetupViewController *)_delegate;
    parent.activeCellIndexPath = [tableView indexPathForCell:self];
}

- (void)textViewDidChange:(UITextView *)textView
{
    if (textView.contentSize.height > contentRowHeight) {

        contentRowHeight = textView.contentSize.height;

        UITableView *tableView = (UITableView *)self.superview;
        [tableView beginUpdates];
        [tableView endUpdates];

        [textView setFrame:CGRectMake(0, 0, 300.0, textView.contentSize.height)];
    }
}

- (void)textViewDidEndEditing:(UITextView *)textView
{
    if (_delegate && [_delegate respondsToSelector:@selector(tableViewCell:didEndEditingWithLongString:)]) {
        [_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
    }
    UITableView *tableView = (UITableView *)self.superview;
    [tableView deselectRowAtIndexPath:[tableView indexPathForCell:self] animated:YES];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    CGRect editFrame = CGRectInset(self.contentView.frame, 10, 10);

    if (self.textLabel.text && [self.textLabel.text length] != 0) {
        CGSize textSize = [self.textLabel sizeThatFits:CGSizeZero];
        editFrame.origin.x += textSize.width + 10;
        editFrame.size.width -= textSize.width + 10;
        self.textView.textAlignment = NSTextAlignmentRight;
    } else {
        self.textView.textAlignment = NSTextAlignmentLeft;
    }

    self.textView.frame = editFrame;
}

Що створено в cellForRowAtIndexPath , як це:

else if ([paramType isEqualToString:@"longString"]) {
            MyIdentifier = @"AppActionLongString";

            LongStringInputTableViewCell *cell = (LongStringInputTableViewCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
            cell.textLabel.text = [[[_selectedAction objectForKey:@"parameters"] objectAtIndex:indexPath.row] objectForKey:@"name"];
            cell.params = [[_selectedAction objectForKey:@"parameters"] objectAtIndex:indexPath.row];

            cell.textView.text = [results objectAtIndex:indexPath.row];

            return cell;
        }

Просто повернення висоти до змінної в моєму ViewController не є корисним, тому що, як я вже сказав, у таблиці можуть бути декілька цих комірок.

Дякую

2
Це для введення користувача. На даний момент я відправляю його назад в ViewController, використовуючи метод делегації після завершення, і зберігаю кожного в масиві. Коли я змінюю розмір, я зателефоную за методом delegate після кожного ключового входу, щоб перевірити зміну розміру.
додано Автор Darren, джерело
звідки ви отримуєте текст для TextView?
додано Автор Rox, джерело

9 Відповіді

просто коментар

if (cell == nil)

Сподіваюся, це допоможе вам.

2
додано

просто коментар

if (cell == nil)

Сподіваюся, це допоможе вам.

2
додано

Використовуйте цей метод, щоб динамічно змінити розмір вашого табличного перегляду. Спочатку зберігайте вхід користувача в NSMutable Array, а потім перезавантажуйте таблицю. Сподіваюся, це допоможе вам.

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

    NSString *msg =[self.messages objectAtIndex:indexPath.row];
    CGSize  textSize = { 120, 10000.0 };
    CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:15]
                  constrainedToSize:textSize
                      lineBreakMode:UILineBreakModeWordWrap];


return size.height+20;

}

1
додано
Дякую. Я пробував щось на зразок цього раніше. Проблема полягає в тому, що ви встановили ширину до 120. Моя ширина є динамічною, оскільки TextView вперше встановлено на CGRectZero з UIViewAutoresizingFlexibleWidth , тому він заповнює пробіл, який залишився Назва Я не можу отримати посилання на комірку, щоб захопити ширину.
додано Автор Darren, джерело
Клітка має назву мітки зліва, а текстовий перегляд - справа. Ширина textView залежить від ширини назви заголовка.
додано Автор Darren, джерело
Ага, так я маю можливість це зробити. Я спробую це незабаром. Дякую
додано Автор Darren, джерело
Ваш висота має бути гнучким, але ви можете виправити розмір вашої ширини. це може бути 320
додано Автор Rox, джерело
Чи можна отримати ширину заголовка, якщо вона динамічна. потім відніміть її ширину від ширини за замовчуванням та встановіть ширину тексту.
додано Автор Rox, джерело
Гаразд, дайте мені знати, що це допомагає.
додано Автор Rox, джерело

Було б легко, якщо б я міг викликати відповідну клітинку під час heightForRowAtIndexPath, але це викликає нескінченний цикл і аварійне завершення роботи, оскільки цей метод викликається до того, як будь-які комірки створюються навіть. Будь-які інші рішення?

Ти можеш. Я думаю, ви намагаєтеся викликати cellForRowAtIndexPath , що призведе до нескінченного циклу. Але ви, швидше за все, маєте залишити комірку безпосередньо, викликавши dequeueReusableCellWithIdentifier .

Див. реалізацію делегатів перегляду таблиць з TLIndexPathTools . Метод heightForRowAtIndexPath виглядає так:

( EDIT спочатку забув включити метод prototypeForCellIdentifier , який фактично відміняє комірку.)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    id item = [self.dataModel itemAtIndexPath:indexPath];
    NSString *cellId = [self cellIdentifierAtIndexPath:indexPath];
    if (cellId) {
        UITableViewCell *cell = [self prototypeForCellIdentifier:cellId];
        if ([cell conformsToProtocol:@protocol(TLDynamicSizeView)]) {
            id v = (id)cell;
            id data;
            if ([item isKindOfClass:[TLIndexPathItem class]]) {
                TLIndexPathItem *i = (TLIndexPathItem *)item;
                data = i.data;
            } else {
                data = item;
            }
            CGSize computedSize = [v sizeWithData:data];
            return computedSize.height;
        } else {
            return cell.bounds.size.height;
        }
    }

    return 44.0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView prototypeForCellIdentifier:(NSString *)cellIdentifier
{
    UITableViewCell *cell;
    if (cellIdentifier) {
        cell = [self.prototypeCells objectForKey:cellIdentifier];
        if (!cell) {
            if (!self.prototypeCells) {
                self.prototypeCells = [[NSMutableDictionary alloc] init];
            }
            cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
            //TODO this will fail if multiple tables are being used and they have
            //overlapping identifiers. The key needs to be unique to the table
            [self.prototypeCells setObject:cell forKey:cellIdentifier];
        }
    }
    return cell;
}

Це використовує протокол TLDynamicSizeView , який будь-яка клітина може реалізувати, щоб її висота була розрахована автоматично. Ось робочий приклад проекту . Реалізація клітинки протоколу виглядає так:

@implementation DynamicHeightCell

- (void)awakeFromNib
{
    [super awakeFromNib];
    self.originalSize = self.bounds.size;
    self.originalLabelSize = self.label.bounds.size;
}

- (void)configureWithText:(NSString *)text
{
    self.label.text = text;
    [self.label sizeToFit];
}

#pragma mark - TLDynamicSizeView

- (CGSize)sizeWithData:(id)data
{
    [self configureWithText:data];
    //the dynamic size is calculated by taking the original size and incrementing
    //by the change in the label's size after configuring
    CGSize labelSize = self.label.bounds.size;
    CGSize size = self.originalSize;
    size.width += labelSize.width - self.originalLabelSize.width;
    size.height += labelSize.height - self.originalLabelSize.height;
    return size;
}

@end
0
додано

Було б легко, якщо б я міг викликати відповідну клітинку під час heightForRowAtIndexPath, але це викликає нескінченний цикл і аварійне завершення роботи, оскільки цей метод викликається до того, як будь-які комірки створюються навіть. Будь-які інші рішення?

Ти можеш. Я думаю, ви намагаєтеся викликати cellForRowAtIndexPath , що призведе до нескінченного циклу. Але ви, швидше за все, маєте залишити комірку безпосередньо, викликавши dequeueReusableCellWithIdentifier .

Див. реалізацію делегатів перегляду таблиць з TLIndexPathTools . Метод heightForRowAtIndexPath виглядає так:

( EDIT спочатку забув включити метод prototypeForCellIdentifier , який фактично відміняє комірку.)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    id item = [self.dataModel itemAtIndexPath:indexPath];
    NSString *cellId = [self cellIdentifierAtIndexPath:indexPath];
    if (cellId) {
        UITableViewCell *cell = [self prototypeForCellIdentifier:cellId];
        if ([cell conformsToProtocol:@protocol(TLDynamicSizeView)]) {
            id v = (id)cell;
            id data;
            if ([item isKindOfClass:[TLIndexPathItem class]]) {
                TLIndexPathItem *i = (TLIndexPathItem *)item;
                data = i.data;
            } else {
                data = item;
            }
            CGSize computedSize = [v sizeWithData:data];
            return computedSize.height;
        } else {
            return cell.bounds.size.height;
        }
    }

    return 44.0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView prototypeForCellIdentifier:(NSString *)cellIdentifier
{
    UITableViewCell *cell;
    if (cellIdentifier) {
        cell = [self.prototypeCells objectForKey:cellIdentifier];
        if (!cell) {
            if (!self.prototypeCells) {
                self.prototypeCells = [[NSMutableDictionary alloc] init];
            }
            cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
            //TODO this will fail if multiple tables are being used and they have
            //overlapping identifiers. The key needs to be unique to the table
            [self.prototypeCells setObject:cell forKey:cellIdentifier];
        }
    }
    return cell;
}

Це використовує протокол TLDynamicSizeView , який будь-яка клітина може реалізувати, щоб її висота була розрахована автоматично. Ось робочий приклад проекту . Реалізація клітинки протоколу виглядає так:

@implementation DynamicHeightCell

- (void)awakeFromNib
{
    [super awakeFromNib];
    self.originalSize = self.bounds.size;
    self.originalLabelSize = self.label.bounds.size;
}

- (void)configureWithText:(NSString *)text
{
    self.label.text = text;
    [self.label sizeToFit];
}

#pragma mark - TLDynamicSizeView

- (CGSize)sizeWithData:(id)data
{
    [self configureWithText:data];
    //the dynamic size is calculated by taking the original size and incrementing
    //by the change in the label's size after configuring
    CGSize labelSize = self.label.bounds.size;
    CGSize size = self.originalSize;
    size.width += labelSize.width - self.originalLabelSize.width;
    size.height += labelSize.height - self.originalLabelSize.height;
    return size;
}

@end
0
додано

Було б легко, якщо б я міг викликати відповідну клітинку під час heightForRowAtIndexPath, але це викликає нескінченний цикл і аварійне завершення роботи, оскільки цей метод викликається до того, як будь-які комірки створюються навіть. Будь-які інші рішення?

Ти можеш. Я думаю, ви намагаєтеся викликати cellForRowAtIndexPath , що призведе до нескінченного циклу. Але ви, швидше за все, маєте залишити комірку безпосередньо, викликавши dequeueReusableCellWithIdentifier .

Див. реалізацію делегатів перегляду таблиць з TLIndexPathTools . Метод heightForRowAtIndexPath виглядає так:

( EDIT спочатку забув включити метод prototypeForCellIdentifier , який фактично відміняє комірку.)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    id item = [self.dataModel itemAtIndexPath:indexPath];
    NSString *cellId = [self cellIdentifierAtIndexPath:indexPath];
    if (cellId) {
        UITableViewCell *cell = [self prototypeForCellIdentifier:cellId];
        if ([cell conformsToProtocol:@protocol(TLDynamicSizeView)]) {
            id v = (id)cell;
            id data;
            if ([item isKindOfClass:[TLIndexPathItem class]]) {
                TLIndexPathItem *i = (TLIndexPathItem *)item;
                data = i.data;
            } else {
                data = item;
            }
            CGSize computedSize = [v sizeWithData:data];
            return computedSize.height;
        } else {
            return cell.bounds.size.height;
        }
    }

    return 44.0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView prototypeForCellIdentifier:(NSString *)cellIdentifier
{
    UITableViewCell *cell;
    if (cellIdentifier) {
        cell = [self.prototypeCells objectForKey:cellIdentifier];
        if (!cell) {
            if (!self.prototypeCells) {
                self.prototypeCells = [[NSMutableDictionary alloc] init];
            }
            cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
            //TODO this will fail if multiple tables are being used and they have
            //overlapping identifiers. The key needs to be unique to the table
            [self.prototypeCells setObject:cell forKey:cellIdentifier];
        }
    }
    return cell;
}

Це використовує протокол TLDynamicSizeView , який будь-яка клітина може реалізувати, щоб її висота була розрахована автоматично. Ось робочий приклад проекту . Реалізація клітинки протоколу виглядає так:

@implementation DynamicHeightCell

- (void)awakeFromNib
{
    [super awakeFromNib];
    self.originalSize = self.bounds.size;
    self.originalLabelSize = self.label.bounds.size;
}

- (void)configureWithText:(NSString *)text
{
    self.label.text = text;
    [self.label sizeToFit];
}

#pragma mark - TLDynamicSizeView

- (CGSize)sizeWithData:(id)data
{
    [self configureWithText:data];
    //the dynamic size is calculated by taking the original size and incrementing
    //by the change in the label's size after configuring
    CGSize labelSize = self.label.bounds.size;
    CGSize size = self.originalSize;
    size.width += labelSize.width - self.originalLabelSize.width;
    size.height += labelSize.height - self.originalLabelSize.height;
    return size;
}

@end
0
додано

Мені потрібен динамічний перегляд висоти стільника на основі розміру тексту, який буде відображатися в цій комірці. Я вирішив це таким чином:

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

            if ([self.conditionsDataArray count]>0)
            {
                Conditions *condition =[self.conditionsDataArray objectAtIndex:indexPath.row];

                int height;

                UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 236, 0)];   //you can set your frame according to your need

                textview.text  = condition.comment;

                textview.autoresizingMask = UIViewAutoresizingFlexibleHeight;

                [tableView addSubview:textview];

                textview.hidden = YES;

                height = textview.contentSize.height;

                NSLog(@"TEXT VIEW HEIGHT %f", textview.contentSize.height);

                [textview removeFromSuperview];

                [textview release];

                return height;
       }

       return 55;  //Default height, if data is in loading state
}

Зверніть увагу, що текстовий вигляд був доданий як Subview, а потім був прихованим, тому обов'язково додайте його як SubView, інакше його висота не буде розглядатися.

0
додано

Мені потрібен динамічний перегляд висоти стільника на основі розміру тексту, який буде відображатися в цій комірці. Я вирішив це таким чином:

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

            if ([self.conditionsDataArray count]>0)
            {
                Conditions *condition =[self.conditionsDataArray objectAtIndex:indexPath.row];

                int height;

                UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 236, 0)];   //you can set your frame according to your need

                textview.text  = condition.comment;

                textview.autoresizingMask = UIViewAutoresizingFlexibleHeight;

                [tableView addSubview:textview];

                textview.hidden = YES;

                height = textview.contentSize.height;

                NSLog(@"TEXT VIEW HEIGHT %f", textview.contentSize.height);

                [textview removeFromSuperview];

                [textview release];

                return height;
       }

       return 55;  //Default height, if data is in loading state
}

Зверніть увагу, що текстовий вигляд був доданий як Subview, а потім був прихованим, тому обов'язково додайте його як SubView, інакше його висота не буде розглядатися.

0
додано

Мені потрібен динамічний перегляд висоти стільника на основі розміру тексту, який буде відображатися в цій комірці. Я вирішив це таким чином:

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

            if ([self.conditionsDataArray count]>0)
            {
                Conditions *condition =[self.conditionsDataArray objectAtIndex:indexPath.row];

                int height;

                UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 236, 0)];   //you can set your frame according to your need

                textview.text  = condition.comment;

                textview.autoresizingMask = UIViewAutoresizingFlexibleHeight;

                [tableView addSubview:textview];

                textview.hidden = YES;

                height = textview.contentSize.height;

                NSLog(@"TEXT VIEW HEIGHT %f", textview.contentSize.height);

                [textview removeFromSuperview];

                [textview release];

                return height;
       }

       return 55;  //Default height, if data is in loading state
}

Зверніть увагу, що текстовий вигляд був доданий як Subview, а потім був прихованим, тому обов'язково додайте його як SubView, інакше його висота не буде розглядатися.

0
додано
IT KPI iOS
IT KPI iOS
74 учасників

Чат обсуждения IOS. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/602

ios_jobs_ua
ios_jobs_ua
27 учасників

Mobile Dev Jobs UA
Mobile Dev Jobs UA
20 учасників

Публикуем вакансии и запросы на поиск работы по направлению iOS, Android, Xamarin, RN и т.д.