web-dev-qa-db-fra.com

Comment faire un UITableViewCell avec un UITextView à l'intérieur, qui ajuste dynamiquement sa hauteur, sur la base du UITextView?

Je voudrais avoir une vue tablew avec un comportement similaire à l'application iPhone Contacts d'Apple: une cellule uitableview avec une vue uitext à l'intérieur, de sorte que lorsque j'écris dans la vue uitextview, la vue uitextview augmente sa hauteur, et donc en conséquence la cellule uitableview ajuste dynamiquement son la taille. J'ai cherché sur tout le Web, ne trouvant que des solutions partielles et un manque d'exemple de code!

s'il vous plaît aidez-moi, je suis désespéré

Tony

42
Tony

En regardant cela, vous devez être quelque peu délicat. Vous devez calculer la hauteur du textView de manière dynamique et en fonction de la hauteur du TextView, vous devez renvoyer la hauteur de la cellule.

C'est très facile et quelque peu délicat ..

C'est le code par lequel vous pouvez calculer la taille de la chaîne ....

Obtenez d'abord la taille de String

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

Ensuite, créez dynamiquement le textView dans la cellule ... en donnant la chaîneSize.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;

} 

Après avoir fait tellement mal à mes doigts, ...... Je pense que c'est assez de code ... et aidera sûrement à résoudre votre problème ..

Bonne chance

37
Ajay Sharma

Créez un UITableViewCell personnalisé et ajoutez votre UITextView au contentView de la cellule.

Dans LayoutSubviews, définissez textView.frame sur contentView.bounds de la cellule (ou faites une autre disposition personnalisée).

Lorsque le contenu textView change (découvert via UITextViewDelegate), faites deux choses:

1) appelez [tableView beginUpdates]; [tableView endUpdates]; Cela forcera la vue de table à recalculer la hauteur de toutes les cellules (appellera tableView:heightForRowAtIndexPath:). Si votre cellule est le délégué de textView, vous devrez trouver comment obtenir un pointeur vers la tableView, mais il existe plusieurs façons d'y parvenir. Ou vous pouvez faire du délégué votre contrôleur de vue ...

2) lorsque tableView:heightForRowAtIndexPath: est appelé pour cette cellule, renvoyez le textView.contentSize.height. Vous pouvez obtenir votre cellulaire à partir d'ici en appelant [tableView cellForRowAtIndexPath]; Ou si vous n'avez qu'une de ces cellules, mettez en cache un pointeur dans votre viewController.

12
TomSwift

Le seul problème que j'ai trouvé avec la réponse acceptée était que nous allouons UITextView à chaque fois. J'ai trouvé que cela soulevait des problèmes avec la saisie dans la vue et la mise à jour immédiate du texte et le maintien de la vue en tant que premier répondant. Lorsque j'essayais de recharger la cellule avec la nouvelle hauteur, j'essayais ensuite d'ajouter une nouvelle textView.

Pour cette raison, j'ai trouvé une méthode légèrement différente pour atteindre le même objectif. Espérons que cette approche différente pourrait aider les personnes qui ont du mal à implémenter le code ci-dessus.

1) Dans le fichier d'en-tête, définissez une variable pour la hauteur du texte et textView:

UITextView * _textView;
NSInteger _textHeight;

La définition d'une variable signifie que nous pouvons charger la vue à une certaine hauteur si nous chargeons du texte dans textView et réduit également la complexité.

2) Chargez la vue texte et ajoutez-la à notre cellule

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

L'utilisation de keeplayout nous a permis de garder notre champ de texte pour toujours rester à la même hauteur que la cellule. Nous ajoutons également notre UITextView une seule fois.

3) Ajoutez le code pour calculer la hauteur du texte

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

J'en ai essayé beaucoup et j'ai trouvé que cela fonctionnait le mieux

4) Ajoutez un peu de logique dans la hauteur des cellules pour en profiter:

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

Évidemment, nous avons besoin d'un peu plus de hauteur que la hauteur de notre texte, j'ai donc ajouté une quantité de coussin supplémentaire qui peut être expérimentée.

5) Actualisez la vue à chaque fois qu'un caractère est tapé pour vérifier si nous devons augmenter la taille:

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

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

       _textHeight = [self getHeightOfText:textView.text];

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

Dans cette section, nous obtenons la hauteur du texte à chaque fois que l'utilisateur tape.

Ensuite, bien que nous utilisions notre valeur stockée et comparons la valeur actuelle à la valeur stockée. Évidemment, si ce sont les mêmes, il est inutile de rafraîchir la vue. S'ils sont différents, nous mettons à jour la valeur, puis actualisons notre table.

Ce bit, j'ai trouvé une bonne réponse sur stackOverflow montrant comment nous pouvons actualiser uniquement les hauteurs du tableau au lieu de la cellule elle-même. Pourquoi rafraîchir la cellule quand on n'en a pas besoin? Cela signifie qu'une fois que cela est appelé, la hauteur de cellule est mise à jour et augmente bien.

Quoi qu'il en soit, j'ai trouvé que cela fonctionnait très bien et était assez simple pour pouvoir être assemblé ou avoir différentes parties prises et insérées dans d'autres morceaux de code.

Props à la réponse acceptée qui a été pillée pour diverses pièces le long du chemin, mais j'espère également que cette réponse aidera certaines personnes qui ont les mêmes difficultés que moi.

3
simon_smiley

J'ai écrit mes apprentissages et ma solution pour calculer la hauteur UITableViewCell basée sur une UITextView intérieure sur mon blog. La publication contient le code qui fonctionne pour les applications universelles, à la fois les styles de vue tabulaire et l'autorotation.

2
dennisreimann

J'édite la réponse de TomSwift qui est la meilleure façon de le faire:

voici mon code cellulaire (en Swift)

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

pour l'explication, la vue du tableau des cellules est une propriété faible de la cellule, donc je peux lui dire de mettre à jour la disposition lorsque l'utilisateur saisit du texte. La hauteur de la cellule est la somme de sa contrainte supérieure à contentView, sa contrainte inférieure à contentView et textView.contantSize.height qui est également égale à la hauteur constante textView

enter image description here

1
Vassily

Enfin, je l'ai fait fonctionner. Le problème principal est de savoir comment obtenir la largeur correcte de contentView de la cellule. La largeur codée en dur ne fonctionne pas dans tous les cas, car elle peut varier en fonction du style de table simple/groupé, des accessoires ajoutés ou de la disposition paysage/portrait. La seule façon d'obtenir une largeur correcte à 100% est de la demander à un objet cellule. Je crée donc une cellule directement dans heightForRowAtIndexPath et la stocke dans le cache, puis cette cellule mise en cache sera retournée par la méthode cellForRowAtIndexPath. Un autre problème est de savoir comment forcer la cellule à mettre en page ses sous-vues avant de l'utiliser. Cela peut être fait si nous ajoutons temporairement une cellule au tableView et mettons à jour le cadre de la cellule avec la largeur de tabelView. Après cela, toutes les sous-vues seront mises en page de la bonne manière. Ici est la façon dont je l'ai fait fonctionner dans ma bibliothèque TableKit .

1
onegray

Vous devez renvoyer la hauteur correcte dans la méthode déléguée heightForRowAtIndexPath.

0
Rengers

Essayez le code suivant:

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
Sujith Thankachan