web-dev-qa-db-fra.com

Problème de hauteur dynamique pour les cellules UITableView (Swift)

Du texte dynamique de longueur variable est injecté dans les étiquettes de cellules tableview. Pour que les hauteurs des cellules table de table soient dimensionnées de manière dynamique, j'ai implémenté dans viewDidLoad():

self.tableView.estimatedRowHeight = 88.0
self.tableView.rowHeight = UITableViewAutomaticDimension

Cela fonctionne bien pour les cellules sur lesquelles le défilement doit encore être effectué (la variable UITableViewAutomaticDimention étant appelée lors du défilement vers la cellule), mais pas pour les cellules initialement affichées à l'écran lors du chargement de données dans le tableau.

J'ai simplement essayé de recharger les données (comme suggéré dans de nombreuses autres ressources):

self.tableView.reloadData()

viewDidAppear() et viewWillAppear() et ce fut en vain. Je suis perdu. Quelqu'un sait-il comment faire en sorte que xcode rende la hauteur dynamique des cellules chargées initialement à l'écran? 

S'il vous plaît laissez-moi savoir, s'il y a une meilleure méthode alternative.

48
simplexity

Essaye ça:

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

MODIFIER

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

Swift 4

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Swift 4.2

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

Définir ci-dessus les deux méthodes.
Cela résout le problème.

PS: Les contraintes du haut et du bas sont nécessaires pour que cela fonctionne.

Voici un exemple

88
iDhaval

Utilisez ceci:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300

et n'utilisez pas: heightForRowAtIndexPath fonction déléguée

En outre, dans le story-board, ne définissez pas la hauteur de l'étiquette contenant une grande quantité de données. Donnez-lui top, bottom, leading, trailing contraintes. 

29
ami rt

Swift 3

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160

ET!.

12
Vladimir Vozniak

Ce bogue étrange a été résolu grâce aux paramètres d'Interface Builder, les autres réponses n'ayant pas résolu le problème.

Tout ce que j’ai fait, c’est de rendre la taille de l’étiquette par défaut plus grande que le contenu potentiel et de la refléter dans la hauteur estimatedRowHeight. Auparavant, je définissais la hauteur de ligne par défaut dans Interface Builder sur 88px et la reflétait comme suit dans mon contrôleur viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

Mais ça n'a pas marché. Je me suis donc rendu compte que le contenu ne deviendrait jamais plus volumineux que peut-être 100px; j'ai donc défini la hauteur de cellule par défaut sur 108px (plus grand que le contenu potentiel) et l'a reflété de la même manière dans le contrôleur viewDidLoad():

self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 108.0

Cela a permis au code de rétrécir les étiquettes initiales à la taille correcte. En d’autres termes, sa taille n’a jamais été aussi grande, mais elle peut toujours être réduite ... De plus, aucun self.tableView.reloadData() supplémentaire n’a été nécessaire dans viewWillAppear().

Je sais que cela ne couvre pas les tailles de contenu très variables, mais cela a fonctionné dans ma situation où le contenu avait un nombre de caractères maximal possible.

Vous ne savez pas s'il s'agit d'un bogue dans Swift ou Interface Builder, mais cela fonctionne comme un charme. Essaie!

10
simplexity

Définissez les cotes automatiques pour la hauteur et l'estimation de la hauteur de la ligne, puis procédez comme suit:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

Par exemple: si vous avez une étiquette dans votre UITableviewCell, alors,

  • Définir le nombre de lignes = 0 (& mode de saut de ligne = tronquer la queue)
  • Définissez toutes les contraintes (haut, bas, droite à gauche) par rapport à son conteneur superview/cell.
  • Facultatif : définissez la hauteur minimale de l'étiquette, si vous voulez une zone verticale minimale couverte par l'étiquette, même en l'absence de données.

Voici un exemple d'étiquette avec des contraintes de hauteur dynamiques.

enter image description here

7
Krunal

Cellule de dimensionnement dynamique de UITableView requis 2 choses 

  1. Définir la bonne contrainte de votre vue à l'intérieur de la cellule de vue de tableau (la plupart du temps, cela inclut de donner à votre vue les contraintes de haut, de bas et de vérification appropriées)
  2. Appel de ces propriétés de TableView dans viewDidLoad ()

     tableView.rowHeight = UITableViewAutomaticDimension
    
     tableView.estimatedRowHeight = 140
    

This est un excellent didacticiel sur l'auto-dimensionnement (cellules de vue de tableau dynamique) écrit dans Swift 3.

7
osama

Pour Swift 3, vous pouvez utiliser les éléments suivants:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
4
Ahmed Lotfy

Essayer

override func viewWillAppear(animated: Bool) {
    self.tableView.layoutSubviews()
}

J'ai eu le même problème et ça marche pour moi.

2
Maickell Vilela

Pour que la taille automatique de UITableViewCell fonctionne, assurez-vous de bien effectuer les modifications suivantes:

  • Dans Storyboard, votre UITableView ne doit contenir que des cellules prototypes dynamiques (il ne doit pas utiliser de cellules statiques ), Sinon le redimensionnement automatique ne fonctionnera pas. 
  • Dans Storyboard, votre UILabel de UITableViewCell a été configurée pour les 4 contraintes suivantes: contraintes supérieure, inférieure, Principales et de fin.
  • Dans Storyboard, le nombre de lignes de votre UITableViewCell UILabel doit être 0
  • Dans la fonction ViewDidLoad de votre UIViewController définie sous les propriétés UITableView:

    self.tableView.estimatedRowHeight = <minimum cell height> 
    self.tableView.rowHeight = UITableViewAutomaticDimension
    
2
Anshul Sharma

Dans mon cas - dans le storyboard, j'avais deux étiquettes comme dans l'image ci-dessous, les deux étiquettes avaient les valeurs de largeur souhaitées définies avant que je ne les rende égales. une fois que vous avez désélectionné, cela changera en automatique, et comme d'habitude, avoir ci-dessous devrait fonctionner comme un charme.

1.rowHeight = UITableView.automaticDimension, and
2.estimatedRowHeight = 100(In my case).
3.make sure label number of lines is zero.

enter image description here

1
virtplay

Votre solution m'a simplement inspiré et j'ai essayé une autre méthode.

Essayez d’ajouter tableView.reloadData() à viewDidAppear().

Cela fonctionne pour moi.

Je pense que les choses derrière le défilement sont "les mêmes" que reloadData. Lorsque vous faites défiler l'écran, c'est comme si vous appeliez reloadData() quand viewDidAppear.

Si cela fonctionne, répondez svp cette réponse afin que je puisse être sûr de cette solution.

1
Kang Cheng

Pour Swift, j'ai aussi vérifié cette réponse dans iOS 9.0 et iOS 11 (Xcode 9.3)

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

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Ici, vous devez ajouter contraintes en haut, en bas, à droite et à gauche

1
iOS

J'utilise ces

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return 100
}
1
gms

Malheureusement, je ne suis pas sûr de ce qui me manquait. Les méthodes ci-dessus ne me permettent pas d'obtenir la hauteur de la cellule xib ni de laisser la fonction layoutifneeded () ou UITableView.automaticDimension pour effectuer le calcul de la hauteur. J'ai cherché et essayé pendant 3 à 4 nuits mais je n'ai pas pu trouver de réponse. Certaines réponses ici ou sur un autre post m'ont donné des indications sur la solution de contournement. C'est une méthode stupide mais ça marche. Ajoutez simplement toutes vos cellules dans un tableau. Et puis définissez la sortie de chacune de vos contraintes de hauteur dans le storyboard xib. Enfin, ajoutez-les dans la méthode heightForRowAt. C'est tout simplement si vous n'êtes pas familier avec ces API.

Swift 4.2

CustomCell.Swift

@IBOutlet weak var textViewOneHeight: NSLayoutConstraint!
@IBOutlet weak var textViewTwoHeight: NSLayoutConstraint!
@IBOutlet weak var textViewThreeHeight: NSLayoutConstraint!

@IBOutlet weak var textViewFourHeight: NSLayoutConstraint!
@IBOutlet weak var textViewFiveHeight: NSLayoutConstraint!

MyTableViewVC.Swift

.
.
var myCustomCells:[CustomCell] = []
.
.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell

.
.
myCustomCells.append(cell)
return cell

}


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

   let totalHeight = myCustomCells[indexPath.row].textViewOneHeight.constant + myCustomCells[indexPath.row].textViewTwoHeight.constant +  myCustomCells[indexPath.row].textViewThreeHeight.constant + myCustomCells[indexPath.row].textViewFourHeight.constant + myCustomCells[indexPath.row].textViewFiveHeight.constant

  return totalHeight + 40 //some magic number


}
1
William Tong

En plus de ce que d'autres ont dit, 

CONFIGUEZ LES CONTRAINTES DE VOTRE LABEL PAR RAPPORT À LA SUPERVIEW!

Par conséquent, au lieu de placer les contraintes de votre étiquette par rapport aux autres éléments qui l’entourent, limitez-les à la vue de contenu de la cellule de la table.

Ensuite, assurez-vous que la hauteur de votre étiquette est supérieure ou égale à 0 et que le nombre de lignes est défini sur 0. 

Ensuite, dans ViewDidLoad, ajoutez:

tableView.estimatedRowHeight = 695

tableView.rowHeight = UITableViewAutomaticDimension

0
Will Said

Pour Swift 4.2

@IBOutlet weak var tableVw: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Set self as tableView delegate
    tableVw.delegate = self

    tableVw.rowHeight = UITableView.automaticDimension
    tableVw.estimatedRowHeight = UITableView.automaticDimension
}

// UITableViewDelegate Method 
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    return UITableView.automaticDimension
}

Bonne codage :)

0
Ariven Nadar

Lorsque vous utilisez un UITableView statique, je règle toutes les valeurs dans le UILabels, puis appelle tableView.reloadData().

0
Zandor Smith
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0

Et n'oubliez pas d'ajouter contraintes de boutons pour l'étiquette

0
Vineesh TP

Pour l’objectif C, c’est une de mes solutions de Nice. ça a fonctionné pour moi.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row];
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}

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

Nous devons appliquer ces 2 changements.

1)cell.textLabel.numberOfLines = 0;
  cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;

2)return UITableViewAutomaticDimension;
0
iOS

J'avais également eu ce problème au départ, j'avais résolu le problème avec ce code Essayez d'éviter l'utilisation de self.tableView.reloadData() au lieu de ce code pour la hauteur dynamique.

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
0
ShujatAli

C'est simple lorsque vous faites 2 choses:

  1. régler la hauteur automatique

    tableView.rowHeight = UITableView.automaticDimension

  2. créer toutes les TableViewCells avec COMPLET des contraintes de haut en bas. Le dernier élément ** DOIT ** définir un espacement inférieur pour terminer la cellule.

Ainsi, le moteur de présentation peut calculer la hauteur de la cellule et appliquer la valeur correctement.

0
Karsten

Vous devez simplement définir toutes les contraintes pour HAUT, BAS et HAUTEUR pour chaque objet de la vue cellule/vues et supprimer existe milieu Y position si ont . Parce que là où vous ne l'avez pas fait, place des artefacts sur d'autres vues.

0
Gennady Dmitrik