web-dev-qa-db-fra.com

Comment redimensionner UITableViewCell en fonction de son contenu?

J'ai un UITableview avec plusieurs TableViewCells réutilisables. Dans une cellule, j'ai une UITextView, qui se redimensionne pour s'adapter à son contenu. Maintenant, je "juste" dois redimensionner la contentView de la TableViewCell, afin que je puisse lire le texte while. J'ai déjà essayé: 

cell2.contentView.bounds.size.height = cell2.discriptionTextView.bounds.size.height; 

Ou: 

cell2.contentView.frame = CGRectMake(0, cell2.discriptionTextView.bounds.Origin.y,     
cell2.discriptionTextView.bounds.size.width,     
cell2.discriptionTextView.bounds.size.height); 

Dans la méthode:

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

Mais ça ne marchera pas.

Est-ce que quelqu'un sait comment faire ça?

Nouveau code: 

    @implementation AppDetail

    CGFloat height;
    …

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

    cell2.TextView.text = self.text;
            [cell2.TextView sizeToFit];
            height = CGRectGetHeight(cell2.TextView.bounds);
     …
    }

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

        if (indexPath.row == 0) {
            return 143;
        }
        if (indexPath.row == 1) {
            return height;
        }

        return 0;
    }
19

Vous devez implémenter heightForRowAtIndexPath.

Supposons que les données à afficher dans textView soient stockées dans un NSArray.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
 CGFloat cellheight = 30; //assuming that your TextView's Origin.y is 30 and TextView is the last UI element in your cell

 NSString *text = (NSString *)[textArray objectAtIndex:indexpath.row];
 UIFont *font = [UIFont systemFontOfSize:14];// The font should be the same as that of your textView
 CGSize constraintSize = CGSizeMake(maxWidth, CGFLOAT_MAX);// maxWidth = max width for the textView

 CGSize size = [text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

 cellHeight += size.height; //you can also add a cell padding if you want some space below textView

}
7
dRAGONAIR

Vous pouvez uniquement redimensionner un UITableViewCell dans la méthode déléguée tableView:heightForRowAtIndexPath:.

Vous devez estimer quelle sera la taille du texte lorsque cette méthode sera appelée pour chaque ligne lors du chargement de la tableView.

C'est ce que j'ai fait pour résoudre le problème.

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
     NSString * yourText = self.myArrayWithTextInIt[indexPath.row]; // or however you are getting the text
     return additionalSpaceNeeded + [self heightForText:yourText];
 }

 -(CGFloat)heightForText:(NSString *)text
 {
   NSInteger MAX_HEIGHT = 2000;
   UITextView * textView = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, WIDTH_OF_TEXTVIEW, MAX_HEIGHT)];
   textView.text = text;
   textView.font = // your font
   [textView sizeToFit];
   return textView.frame.size.height;
  }

MODIFIER

Bien que j'ai utilisé cette solution pendant un certain temps, j'ai trouvé une solution plus optimale que je vous recommanderais, car elle ne nécessite pas l'allocation d'un textView complet pour fonctionner et peut gérer un texte supérieur à 2000.

-(CGFloat)heightForTextViewRectWithWidth:(CGFloat)width andText:(NSString *)text
{
    UIFont * font = [UIFont systemFontOfSize:12.0f];

    // this returns us the size of the text for a rect but assumes 0, 0 Origin
    CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: font}];

    // so we calculate the area
    CGFloat area = size.height * size.width;

    CGFloat buffer = whateverExtraBufferYouNeed.0f;

    // and then return the new height which is the area divided by the width
    // Basically area = h * w
    // area / width = h
    // for w we use the width of the actual text view
    return floor(area/width) + buffer;
}
17
AdamG

Comme @Rob Norback l'a dit, il existe quelque chose appelé UITableViewAutomaticDimension.

Pour Swift, le moyen le plus simple de redimensionner le contenu de UITableViewCell à la volée consiste simplement à ajouter ceci.

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
     return UITableViewAutomaticDimension
}
15
r_19

Voici une version mise à jour pour iOS 7+ qui est plus propre (pas de méthode supplémentaire) 

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UIFont * font = [UIFont systemFontOfSize:15.0f];
        NSString *text = [getYourTextArray objectAtIndex:indexPath.row];
        CGFloat height = [text boundingRectWithSize:CGSizeMake(self.tableView.frame.size.width, maxHeight) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName: font} context:nil].size.height;

        return height + additionalHeightBuffer;
    }
13
enc_life

Je préfère cette solution de Jure

  • Commencez par définir les contraintes de textview à épingler avec son aperçu (le contenu de la cellule dans ce cas).
  • Désactiver textView.scrollEnabled
  • Ensemble 

    table.rowHeight = UITableViewAutomaticDimension;
    tableView.estimatedRowHeight = 44;
    

    Si finalement, votre code ne fonctionne pas, utilisez plutôt ceci

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return UITableViewAutomaticDimension;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return 44;
    }
    
  • Implémentez UITextViewDelegate comme ceci:

    - (void)textViewDidChange:(UITextView *)textView {
         CGPoint currentOffset = self.tableView.contentOffset;
         [UIView setAnimationsEnabled:NO];
         [self.tableView beginUpdates];
         [self.tableView endUpdates];
         [UIView setAnimationsEnabled:YES];
         [self.tableView setContentOffset:currentOffset animated:NO];
      }
    
3
samthui7

Ce fil de discussion a pris pas mal de temps, mais dans iOS 8, UITableViewAutomaticDimension a été introduit. Pour que cela fonctionne, vous devez définir des contraintes de haut en bas de la cellule, comme une vue en défilement. Mais après cela, ajoutez simplement le code suivant à viewDidLoad():

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 122.0

Assurez-vous que votre hauteur estimée est aussi proche que possible de la réalité, sinon vous aurez du défilement buggé.

2
Rob Norback

L'ajout de ces deux méthodes à ViewController avec UITableViewAutomaticDimension devrait faire l'affaire. Cela a fonctionné pour moi lors de l'intégration d'une UITextView dans une UITableViewCell avec un texte de longueur variable.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}
1
Stephen

Dans le cas d'une sous-vue UILabel dans UITableViewCell, j'ai effectué le redimensionnement automatique de l'étiquette en définissant simplement les contraintes de l'étiquette (à l'aide du storyboard, Xcode 8.3.2).

Cela fonctionne car apparemment le comportement par défaut de l'étiquette et de la cellule est sizeToFit. Même chose devrait fonctionner pour UITextView.

0
mark