web-dev-qa-db-fra.com

UILabel dans UITableViewCell avec mise en page automatique a une hauteur incorrecte

J'ai une UITableView avec des cellules qui ont une hauteur fixe de 100 points. Les cellules sont créées dans un fichier xib qui utilise 3 contraintes pour épingler une UILabel aux bords gauche, droit et supérieur de la contentView de la cellule. La priorité d'accrochage vertical de l'étiquette est définie sur 1 000 car je souhaite que la hauteur de la cellule soit aussi petite que possible.

Lorsque la largeur de la cellule dans le fichier xib est définie sur 320 points, identique à la largeur de la table dans l'iPhone, la fonction de lecture automatique fonctionne comme prévu. Cependant, lorsque je règle la largeur de la cellule sur moins de 320 points, j'obtiens des résultats inattendus. (Je souhaite utiliser la même cellule dans tableViews qui a des largeurs différentes, par exemple dans une application universelle)

Par exemple: lorsque je fixe la largeur à 224 points et que je donne à l'étiquette un texte qui occupe 2 lignes à cette largeur, la hauteur de l'étiquette augmente pour s'adapter aux 2 lignes, mais lorsque la cellule est redimensionnée à 320 points une tableView de cette largeur, le texte ne prend qu'une ligne, mais la hauteur de l'étiquette reste à 2 lignes.

J'ai mis un exemple de projet sur GitHub pour illustrer le problème: https://github.com/bluecrowbar/CellLayout

Existe-t-il un moyen de toujours redimensionner la UILabel pour qu'elle épouse le contenu de son texte?

21

Ajouter ceci dans la sous-classe de cellule fonctionne:

- (void)layoutSubviews
{
    [super layoutSubviews];
    [self.contentView layoutIfNeeded];
    self.myLabel.preferredMaxLayoutWidth = self.myLabel.frame.size.width;
}

J'ai trouvé ceci sur http://useyourloaf.com/blog/2014/02/14/table-view-cells-with-varying-row-heights.html .

Update 1: Cette réponse concernait iOS 7. Je trouve que la disposition automatique dans les cellules de la vue tableau est très peu fiable depuis iOS 8, même pour des dispositions très simples. Après de nombreuses expériences, je suis (pour la plupart) retourné à la mise en page manuelle et au calcul manuel de la hauteur de la cellule.

Mise à jour 2: J'ai effectué des tests sur iOS 9 et il semble que UITableViewAutomaticDimension fonctionne enfin comme annoncé. Yay!

65

Bug stupide! J'ai perdu presque un jour dans ce problème et je l'ai finalement résolu avec la solution de Steven Vandewghe.

Version Swift:

override func layoutSubviews() {
    super.layoutSubviews()
    self.contentView.layoutIfNeeded()
    self.myLabel.preferredMaxLayoutWidth = self.myLabel.frame.size.width
}
14
Tom Calmon

Puisque vous contraignez la variable width de l'étiquette, la intrinsicContentSize honore cette width et ajuste la height. Et cela crée un problème de poulet et d’œufs:

  1. Le résultat de la disposition automatique de la cellule dépend de la intrinsicContentSize de l'étiquette.
  2. La variable intrinsicContentSize de l'étiquette dépend de la widthde l'étiquette.
  3. La variable width de l'étiquette dépend du résultat de la disposition automatique de la cellule.

Donc, ce qui se passe, c'est que la disposition de la cellule n'est calculée qu'une seule fois dans laquelle (2) est basé sur la largeur statique dans le fichier XIB, ce qui donne la mauvaise étiquette height.

Vous pouvez résoudre ce problème en itérant. Autrement dit, répétez le calcul de la disposition automatique après que la variable width de l'étiquette ait été définie par le premier calcul. Quelque chose comme ça dans votre cellule personnalisée fonctionnera:

- (void)drawRect:(CGRect)rect
{
    CGSize size = self.myLabel.bounds.size;
    // tell the label to size itself based on the current width
    [self.myLabel sizeToFit];
    if (!CGSizeEqualToSize(size, self.myLabel.bounds.size)) {
        [self setNeedsUpdateConstraints];
        [self updateConstraintsIfNeeded];
    }
    [super drawRect:rect];
}

solution originale ne fonctionne pas de manière fiable:

- (void)layoutSubviews
{
    [super layoutSubviews];
    // check for need to re-evaluate constraints on next run loop
    // cycle after the layout has been finalized
    dispatch_async(dispatch_get_main_queue(), ^{
        CGSize size = self.myLabel.bounds.size;
        // tell the label to size itself based on the current width
        [self.myLabel sizeToFit];
        if (!CGSizeEqualToSize(size, self.myLabel.bounds.size)) {
            [self setNeedsUpdateConstraints];
            [self updateConstraintsIfNeeded];
        }
    });
}
3
Timothy Moose

J'ajoute généralement ces deux lignes à viewDidLoad ()

    self.tableView.rowHeight = UITableViewAutomaticDimension
    self.tableView.estimatedRowHeight = 96

Cela redimensionnera automatiquement la cellule

0
Maria