Redimensionarea dinamică a UITableViewCell bazată pe introducerea textului

Încerc să redimensionez dinamic un UITableViewCell pe baza înălțimii UITextView conținută în ele. Există o mulțime de soluții prin păstrarea unui pointer la UITextView și obținerea dimensiunii conținutului în heightForRowAtIndexPath cu toate acestea când întregul tabel este creat dinamic cu un număr necunoscut de rânduri și numărul necunoscut al rândurilor acestora conține UITextView ; acest lucru nu este posibil. Ar fi ușor dacă aș putea apela celula respectivă în timpul heightForRowAtIndexPath , dar care provoacă o buclă infinită și un accident, așa cum se numește această metodă, înainte ca orice celulă să fie chiar creată. Orice alte soluții?

Folosesc o subclasă UITableViewCell pentru celula mea, după cum urmează:

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

Ceea ce este creat în cellForRowAtIndexPath , astfel:

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

Pur și simplu trecerea înapoi a înălțimii la o variabilă în ViewController nu este bună, deoarece, așa cum am spus, ar putea exista câteva din aceste celule în tabel.

Mulțumiri

2
Este pentru intrarea utilizatorului. În momentul în care îl trimit înapoi la ViewController folosind o metodă delegată după finalizarea și stocarea fiecăruia într-o matrice. Când primesc lucrul la redimensionare, voi apela metoda delegat după fiecare intrare cheie pentru a verifica redimensionarea.
adăugat autor Darren, sursa
de unde primiți textul pentru TextView?
adăugat autor Rox, sursa

9 răspunsuri

doar comentariu

if (cell == nil)

Sper că acest lucru vă va ajuta.

2
adăugat

doar comentariu

if (cell == nil)

Sper că acest lucru vă va ajuta.

2
adăugat

Utilizați această metodă pentru a redimensiona dinamic tableviewCell. Mai întâi stocați intrarea utilizatorului în NSMutable Array și după aceea reîncărcați tabelul. Sper că vă va ajuta.

-(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
adăugat
Mulțumiri. Am încercat ceva de genul asta mai devreme. Problema aici este că ați setat lățimea la 120. Lățimea mea este dinamică, deoarece TextView este setat mai întâi la CGRectZero cu UIViewAutoresizingFlexibleWidth pentru a umple spațiul rămas Titlu. Nu pot să mă refer la celulă pentru a apuca lățimea.
adăugat autor Darren, sursa
Celula are o etichetă de titlu în stânga și textView în partea dreaptă. Lățimea textuluiView depinde de lățimea etichetei de titlu.
adăugat autor Darren, sursa
Aha, da, ar trebui să fac asta. O să încerc asta în curând. Mulțumiri
adăugat autor Darren, sursa
Înălțimea dvs. ar trebui să fie flexibilă, dar puteți remedia dimensiunea lățimii. poate fi 320
adăugat autor Rox, sursa
Poți obține u latimea etichetei de titlu dacă este dinamică. apoi scade lățimea de la lățimea implicită și setați lățimea textului.
adăugat autor Rox, sursa
bine, spune-mi că ajută.
adăugat autor Rox, sursa

Ar fi ușor dacă aș putea apela celula respectivă în timpul înălțimiiForRowAtIndexPath, dar care provoacă o buclă infinită și un accident, așa cum se numește această metodă înainte ca orice celulă să fie chiar creată. Orice alte soluții?

Poti. Aș ghici că încercați să apelați cellForRowAtIndexPath , ceea ce va provoca o buclă infinită. Dar ar trebui mai degrabă să deghizați celula direct apelând dequeueReusableCellWithIdentifier .

Consultați implementarea delegatului în vizualizarea tabelului din TLIndexPathTools . Metoda heightForRowAtIndexPath arată astfel:

( EDIT a uitat inițial să includeți metoda prototypeForCellIdentifier care deghizează de fapt celula.)

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

Aceasta utilizează un protocol TLDynamicSizeView pe care orice celulă îl poate implementa pentru a-l calcula automat înălțimea. Aici este un exemplu de proiect . Implementarea de către celulă a protocolului arată astfel:

@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
adăugat

Ar fi ușor dacă aș putea apela celula respectivă în timpul înălțimiiForRowAtIndexPath, dar care provoacă o buclă infinită și un accident, așa cum se numește această metodă înainte ca orice celulă să fie chiar creată. Orice alte soluții?

Poti. Aș ghici că încercați să apelați cellForRowAtIndexPath , ceea ce va provoca o buclă infinită. Dar ar trebui mai degrabă să deghizați celula direct apelând dequeueReusableCellWithIdentifier .

Consultați implementarea delegatului în vizualizarea tabelului din TLIndexPathTools . Metoda heightForRowAtIndexPath arată astfel:

( EDIT a uitat inițial să includeți metoda prototypeForCellIdentifier care deghizează de fapt celula.)

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

Aceasta utilizează un protocol TLDynamicSizeView pe care orice celulă îl poate implementa pentru a-l calcula automat înălțimea. Aici este un exemplu de proiect . Implementarea de către celulă a protocolului arată astfel:

@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
adăugat

Ar fi ușor dacă aș putea apela celula respectivă în timpul înălțimiiForRowAtIndexPath, dar care provoacă o buclă infinită și un accident, așa cum se numește această metodă înainte ca orice celulă să fie chiar creată. Orice alte soluții?

Poti. Aș ghici că încercați să apelați cellForRowAtIndexPath , ceea ce va provoca o buclă infinită. Dar ar trebui mai degrabă să deghizați celula direct apelând dequeueReusableCellWithIdentifier .

Consultați implementarea delegatului în vizualizarea tabelului din TLIndexPathTools . Metoda heightForRowAtIndexPath arată astfel:

( EDIT a uitat inițial să includeți metoda prototypeForCellIdentifier care deghizează de fapt celula.)

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

Aceasta utilizează un protocol TLDynamicSizeView pe care orice celulă îl poate implementa pentru a-l calcula automat înălțimea. Aici este un exemplu de proiect . Implementarea de către celulă a protocolului arată astfel:

@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
adăugat

Aveam nevoie de o înălțime dinamică a celulei din tabel, în funcție de cantitatea de text care trebuie afișată în acea celulă. Am rezolvat-o în felul următor:

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

Observați că textul a fost adăugat sub formă de Subview și apoi a fost ascuns, deci asigurați-vă că îl adăugați ca SubView altfel înălțimea nu va fi luată în considerare.

0
adăugat

Aveam nevoie de o înălțime dinamică a celulei din tabel, în funcție de cantitatea de text care trebuie afișată în acea celulă. Am rezolvat-o în felul următor:

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

Observați că textul a fost adăugat sub formă de Subview și apoi a fost ascuns, deci asigurați-vă că îl adăugați ca SubView altfel înălțimea nu va fi luată în considerare.

0
adăugat

Aveam nevoie de o înălțime dinamică a celulei din tabel, în funcție de cantitatea de text care trebuie afișată în acea celulă. Am rezolvat-o în felul următor:

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

Observați că textul a fost adăugat sub formă de Subview și apoi a fost ascuns, deci asigurați-vă că îl adăugați ca SubView altfel înălțimea nu va fi luată în considerare.

0
adăugat
iOS dezvoltatori, România — Moldova
iOS dezvoltatori, România — Moldova
18 participanți

Parteneri: ciupacabra.com, @php_ro, @js_ro, @node_ro, @seo_ro Android: @ro_android