UITableViewCell dynamisch aanpassen op basis van tekstinvoer

Ik probeer een aantal UITableViewCell 's dynamisch aan te passen op basis van de hoogte van de UITextView die er in zit. Er zijn heel veel oplossingen om dit te doen door een aanwijzer naar de UITextView te houden en de inhoud in heightForRowAtIndexPath te krijgen, maar wanneer de hele tabel dynamisch is gemaakt met een onbekend aantal rijen en een onbekend aantal rijen bevat UITextView is dit is gewoon niet mogelijk. Het zou gemakkelijk zijn om de betreffende cel te bellen tijdens heightForRowAtIndexPath , maar dat veroorzaakt een oneindige lus en crasht omdat deze methode wordt aangeroepen voordat er zelfs maar cellen worden gemaakt. Andere oplossingen?

Ik gebruik een UITableViewCell -subklasse voor mijn cel als volgt:

- (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;
}

Wat is gemaakt in cellForRowAtIndexPath zoals dit:

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;
        }

Gewoon de hoogte terugzetten naar een variabele in mijn ViewController is niet goed, want zoals ik al zei, kunnen er verschillende van deze cellen in de tabel zijn.

Bedankt

2
Het is voor gebruikersinvoer. Op het moment stuur ik het terug naar de ViewController met een gedelegeerde methode na voltooiing en sla het allemaal op in een array. Wanneer ik de grootteaanpassing aan het werk krijg, zal ik de gedelegeerde methode na elke toetsinvoer oproepen om te controleren of de grootte verandert.
toegevoegd de auteur Darren, de bron
van waar krijg je de tekst voor TextView?
toegevoegd de auteur Rox, de bron

9 antwoord

gewoon commentaar

if (cell == nil)

Hoop, dit zal je helpen.

2
toegevoegd

gewoon commentaar

if (cell == nil)

Hoop, dit zal je helpen.

2
toegevoegd

Gebruik deze methode om uw tableviewCell dynamisch te verkleinen. Sla eerst de gebruikersinvoer op in NSMutable Array en daarna de herlaadtabel. Ik hoop dat het je zal helpen.

-(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
toegevoegd
Bedankt. Ik heb zoiets eerder geprobeerd. Het probleem hier is dat je breedte hebt ingesteld op 120. Mijn breedte is dynamisch omdat de tekstweergave eerst is ingesteld op CGRectZero met UIViewAutoresizingFlexibleWidth , zodat de ruimte die is overgebleven door de Titel. Ik kan geen verwijzing naar de cel krijgen om de breedte te grijpen.
toegevoegd de auteur Darren, de bron
De cel heeft een titellabel aan de linkerkant en de tekstView aan de rechterkant. De breedte van de tekstweergave is afhankelijk van de breedte van het titellabel.
toegevoegd de auteur Darren, de bron
Aha, ja dat zou ik moeten kunnen doen. Ik zal dat binnenkort proberen. Bedankt
toegevoegd de auteur Darren, de bron
Uw hoogte moet flexibel zijn, maar u kunt uw breedte bepalen. het kan 320 zijn
toegevoegd de auteur Rox, de bron
Kunt u de breedte van het titellabel krijgen als deze dynamisch is? trek vervolgens de breedte van uw standaardbreedte af en stel uw tekstbreedte in.
toegevoegd de auteur Rox, de bron
Oké, laat me weten dat het helpt.
toegevoegd de auteur Rox, de bron

Het zou gemakkelijk zijn als ik de betreffende cel zou kunnen bellen tijdens heightForRowAtIndexPath, maar dat veroorzaakt een oneindige lus en crasht omdat deze methode wordt aangeroepen voordat er zelfs maar cellen worden gemaakt. Nog andere oplossingen?

Jij kan. Ik vermoed dat je probeert om cel ForRowAtIndexPath aan te roepen, wat een oneindige lus zal veroorzaken. Maar u moet de cel liever uit de cel verwijderen door dequeueReusableCellWithIdentifier aan te roepen.

Zie de uitvoering van tabelweergave delegeren van TLIndexPathTools . De methode heightForRowAtIndexPath ziet er als volgt uit:

( EDIT Aanvankelijk vergeten de methode prototypeForCellIdentifier op te nemen die de cel daadwerkelijk uit de wachtrij haalt.)

- (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;
}

Dit gebruikt een protocol TLDynamicSizeView dat elke cel kan implementeren om de hoogte automatisch te laten berekenen. Hier is een werkend voorbeeldproject . De implementatie van het protocol door de cel ziet er als volgt uit:

@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
toegevoegd

Het zou gemakkelijk zijn als ik de betreffende cel zou kunnen bellen tijdens heightForRowAtIndexPath, maar dat veroorzaakt een oneindige lus en crasht omdat deze methode wordt aangeroepen voordat er zelfs maar cellen worden gemaakt. Nog andere oplossingen?

Jij kan. Ik vermoed dat je probeert om cel ForRowAtIndexPath aan te roepen, wat een oneindige lus zal veroorzaken. Maar u moet de cel liever uit de cel verwijderen door dequeueReusableCellWithIdentifier aan te roepen.

Zie de uitvoering van tabelweergave delegeren van TLIndexPathTools . De methode heightForRowAtIndexPath ziet er als volgt uit:

( EDIT Aanvankelijk vergeten de methode prototypeForCellIdentifier op te nemen die de cel daadwerkelijk uit de wachtrij haalt.)

- (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;
}

Dit gebruikt een protocol TLDynamicSizeView dat elke cel kan implementeren om de hoogte automatisch te laten berekenen. Hier is een werkend voorbeeldproject . De implementatie van het protocol door de cel ziet er als volgt uit:

@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
toegevoegd

Het zou gemakkelijk zijn als ik de betreffende cel zou kunnen bellen tijdens heightForRowAtIndexPath, maar dat veroorzaakt een oneindige lus en crasht omdat deze methode wordt aangeroepen voordat er zelfs maar cellen worden gemaakt. Nog andere oplossingen?

Jij kan. Ik vermoed dat je probeert om cel ForRowAtIndexPath aan te roepen, wat een oneindige lus zal veroorzaken. Maar u moet de cel liever uit de cel verwijderen door dequeueReusableCellWithIdentifier aan te roepen.

Zie de uitvoering van tabelweergave delegeren van TLIndexPathTools . De methode heightForRowAtIndexPath ziet er als volgt uit:

( EDIT Aanvankelijk vergeten de methode prototypeForCellIdentifier op te nemen die de cel daadwerkelijk uit de wachtrij haalt.)

- (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;
}

Dit gebruikt een protocol TLDynamicSizeView dat elke cel kan implementeren om de hoogte automatisch te laten berekenen. Hier is een werkend voorbeeldproject . De implementatie van het protocol door de cel ziet er als volgt uit:

@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
toegevoegd

Ik had een dynamische hoogte van de tabelweergave nodig op basis van de hoeveelheid tekst die in die cel moet worden weergegeven. Ik loste het op deze manier op:

    - (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
}

Merk op dat de tekstweergave als Subview is toegevoegd en vervolgens is verborgen, dus zorg ervoor dat u deze als SubView toevoegt, anders wordt de hoogte niet in aanmerking genomen.

0
toegevoegd

Ik had een dynamische hoogte van de tabelweergave nodig op basis van de hoeveelheid tekst die in die cel moet worden weergegeven. Ik loste het op deze manier op:

    - (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
}

Merk op dat de tekstweergave als Subview is toegevoegd en vervolgens is verborgen, dus zorg ervoor dat u deze als SubView toevoegt, anders wordt de hoogte niet in aanmerking genomen.

0
toegevoegd

Ik had een dynamische hoogte van de tabelweergave nodig op basis van de hoeveelheid tekst die in die cel moet worden weergegeven. Ik loste het op deze manier op:

    - (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
}

Merk op dat de tekstweergave als Subview is toegevoegd en vervolgens is verborgen, dus zorg ervoor dat u deze als SubView toevoegt, anders wordt de hoogte niet in aanmerking genomen.

0
toegevoegd