UICollectionView à l'intérieur d'un UITableViewCell - hauteur dynamique?

125

L'un de nos écrans d'application nous oblige à placer un UICollectionViewintérieur d' un fichier UITableViewCell. Cela UICollectionViewaura un nombre dynamique d'éléments, résultant en une hauteur qui doit également être calculée dynamiquement. Cependant, je rencontre des problèmes en essayant de calculer la hauteur de l'encastré UICollectionView.

Notre ensemble a UIViewControllerété créé dans les storyboards et utilise la mise en page automatique. Mais, je ne sais pas comment augmenter dynamiquement la hauteur du en UITableViewCellfonction de la hauteur du UICollectionView.

Quelqu'un peut-il donner des astuces ou des conseils sur la façon d'accomplir cela?

Homme de l'ombre
la source
pouvez-vous en dire un peu plus sur la mise en page que vous essayez de réaliser? La hauteur du UITableViewCelltableau est-elle différente de sa vue de table réelle? Avez-vous besoin d'un défilement vertical sur le UICollectionViewet leUITableView
apouche
3
La hauteur de UITableViewCell est censée être dynamique, en fonction de la hauteur de UICollectionView qui fait partie de la cellule de vue tableau. La disposition de mon UICollectionView est de 4 colonnes et un nombre dynamique de lignes. Donc, avec 100 éléments, j'aurais 4 colonnes et 25 lignes dans mon UICollectionView. La hauteur de la cellule particulière - comme indiqué par heightForRowAtIndexPath d'UITableView - doit pouvoir s'ajuster en fonction de la taille de cette UICollectionView. Est-ce un peu plus clair?
Shadowman
@Shadowman, veuillez me suggérer une solution pour cette situation
Ravi Ojha

Réponses:

127

La bonne réponse est OUI , vous POUVEZ le faire.

J'ai rencontré ce problème il y a quelques semaines. C'est en fait plus facile que vous ne le pensez. Placez vos cellules dans des NIB (ou des storyboards) et épinglez-les pour laisser la mise en page automatique faire tout le travail

Compte tenu de la structure suivante:

Vue de tableau

TableViewCell

CollectionView

CollectionViewCell

CollectionViewCell

CollectionViewCell

[... nombre variable de cellules ou différentes tailles de cellules]

La solution consiste à indiquer à la disposition automatique de calculer d'abord les tailles de collectionViewCell, puis la vue de collection contentSize et de l'utiliser comme taille de votre cellule. C'est la méthode UIView qui "fait la magie":

-(void)systemLayoutSizeFittingSize:(CGSize)targetSize 
     withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority 
           verticalFittingPriority:(UILayoutPriority)verticalFittingPriority

Vous devez définir ici la taille de TableViewCell, qui dans votre cas est contentSize de CollectionView.

CollectionViewCell

Au CollectionViewCell, vous devez indiquer à la cellule de se mettre en page à chaque fois que vous changez de modèle (par exemple: vous définissez un UILabel avec un texte, puis la cellule doit être mise en page à nouveau).

- (void)bindWithModel:(id)model {
    // Do whatever you may need to bind with your data and 
    // tell the collection view cell's contentView to resize
    [self.contentView setNeedsLayout];
}
// Other stuff here...

TableViewCell

Le TableViewCell fait la magie. Il a une sortie à votre CollectionView, permet la mise en page automatique pour les cellules en utilisant CollectionView estimatedItemSize du UICollectionViewFlowLayout .

Ensuite, l'astuce consiste à définir la taille de votre cellule tableView à la méthode systemLayoutSizeFittingSize ... (REMARQUE: iOS8 ou version ultérieure)

NOTE: J'ai essayé d'utiliser la méthode de la hauteur de la cellule de délégué du tableView -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath.mais il est trop tard pour le système de mise en page automatique pour calculer la CollectionView contentSize et parfois vous pouvez trouver de mauvaises cellules redimensionnées.

@implementation TableCell

- (void)awakeFromNib {
    [super awakeFromNib];
    UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;

    // Configure the collectionView
    flow.minimumInteritemSpacing = ...;

    // This enables the magic of auto layout. 
    // Setting estimatedItemSize different to CGSizeZero 
    // on flow Layout enables auto layout for collectionView cells.
    // https://developer.apple.com/videos/play/wwdc2014-226/
    flow.estimatedItemSize = CGSizeMake(1, 1);

    // Disable the scroll on your collection view
    // to avoid running into multiple scroll issues.
    [self.collectionView setScrollEnabled:NO];
}

- (void)bindWithModel:(id)model {
    // Do your stuff here to configure the tableViewCell
    // Tell the cell to redraw its contentView        
    [self.contentView layoutIfNeeded];
}

// THIS IS THE MOST IMPORTANT METHOD
//
// This method tells the auto layout
// You cannot calculate the collectionView content size in any other place, 
// because you run into race condition issues.
// NOTE: Works for iOS 8 or later
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority {

    // With autolayout enabled on collection view's cells we need to force a collection view relayout with the shown size (width)
    self.collectionView.frame = CGRectMake(0, 0, targetSize.width, MAXFLOAT);
    [self.collectionView layoutIfNeeded];

    // If the cell's size has to be exactly the content 
    // Size of the collection View, just return the
    // collectionViewLayout's collectionViewContentSize.

    return [self.collectionView.collectionViewLayout collectionViewContentSize];
}

// Other stuff here...

@end

TableViewController

N'oubliez pas d'activer le système de disposition automatique pour les cellules tableView sur votre TableViewController :

- (void)viewDidLoad {
    [super viewDidLoad];

    // Enable automatic row auto layout calculations        
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    // Set the estimatedRowHeight to a non-0 value to enable auto layout.
    self.tableView.estimatedRowHeight = 10;

}

CRÉDIT: @rbarbera a aidé à résoudre ce problème

Pablo Romeu
la source
4
Ouais. Cela marche. Cela devrait être la réponse acceptée.
csotiriou
1
Un organisme peut-il me fournir un exemple de code? Je veux afficher plusieurs images dans la vue verticale de la collection, qui se trouve à l'intérieur de la cellule tableview ..
Ravi Ojha
4
Enfin, cela a fonctionné pour moi, mais j'ai dû faire une autre astuce: cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), 10000);cela "simulera" une longue cellule avec une longue collectionView, donc la collectionView calculera la taille de toutes ses cellules. Sinon, la collectionView a calculé uniquement les tailles de cellule visibles et a mal défini la hauteur de talbeViewCell.
ingaham
20
lors du réglage de la hauteur du cadre au maximum systemLayoutSizeFittingSize, j'ai rencontré un problème rapidement lors du rechargement de la cellule, les applications semblent rester bloquées après le self.collectionView.layoutIfNeeded(). Je l'ai corrigé en réglant la hauteur du cadre sur 1 plutôt que sur la hauteur maximale. J'espère que cela aide si quelqu'un tombe sur ce problème.
titan
6
Voici ce qui l'a corrigé pour moi - dans systemLayoutSizeFitting, inversez l'ordre de ce qui est affiché dans la réponse actuellement, de sorte que le premier collectionView.layoutIfNeeded()s'exécute, puiscollectionView.frame = CGRect.init(origin: .zero, size: CGSize.init(width: targetSize.width, height: 1))
xaphod
101

Je pense que ma solution est bien plus simple que celle proposée par @PabloRomeu.

Étape 1. Créez une prise de UICollectionViewà UITableViewCell subclass, où UICollectionViewest placée. Laisse, son nom seracollectionView

Étape 2. Ajoutez IB pour la UICollectionViewcontrainte de hauteur et créez également une sortie UITableViewCell subclass. Laissez, son nom sera collectionViewHeight.

Étape 3. Dans tableView:cellForRowAtIndexPath:ajouter du code:

// deque a cell
cell.frame = tableView.bounds;
[cell layoutIfNeeded];
[cell.collectionView reloadData];
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height;
Igor
la source
1
Avez-vous réellement essayé cela? Il ne semble pas possible à la fois de définir une contrainte de hauteur sur la vue de collection et de l'épingler aux marges de la cellule de vue de tableau. Soit vous vous retrouvez avec trop peu de contraintes (d'où un avertissement de taille nulle), soit vous vous retrouvez avec des contraintes conflictuelles (dont l'une est ignorée). Veuillez expliquer comment définir les contraintes de cette solution.
Dale
2
Je l'ai fait fonctionner. J'ajoute des contraintes pour collectionViewtous les côtés UITableViewCellet ensemble tableView.estimatedRowHeight = 44;ettableView.rowHeight = UITableViewAutomaticDimension;
Igor
3
Celui-ci fonctionne comme un champion ... simple et efficace ... merci. Si pour quelqu'un cela ne fonctionne pas, la raison en est probablement que nous devons lier le bas de la vue de collection au bas de la cellule de la vue du tableau. Ensuite, il commencera à fonctionner. Bon codage .. :)
Sebin Roy
2
Cela fonctionnerait-il lorsque l'écran est redimensionné, par exemple en faisant pivoter un iPad? Cela modifierait potentiellement la hauteur de la vue de la collection, et donc la hauteur de la cellule, mais si elle est à l'écran, la cellule ne peut pas nécessairement être rechargée par la vue de table, n'appelant donc jamais la méthode cellForRowAtIndexPath: et ne vous donnant pas la possibilité de changer la constante de contrainte. Il peut cependant être possible de forcer un reloadData.
Carl Lindberg
2
Avez-vous essayé différentes tailles de cellule collectionView? C'était mon problème. Si vous avez des tailles de cellule différentes de collectionView, cela n'a pas fonctionné ... :(
Pablo Romeu
22

Les vues de table et les vues de collection sont des UIScrollViewsous - classes et n'aiment donc pas être intégrées dans une autre vue de défilement car elles essaient de calculer les tailles de contenu, de réutiliser les cellules, etc.

Je vous recommande de n'utiliser qu'une vue de collection pour tous vos besoins.

Vous pouvez le diviser en sections et "traiter" la mise en page de certaines sections comme une vue de tableau et d'autres comme une vue de collection. Après tout, il n'y a rien que vous ne puissiez réaliser avec une vue de collection que vous pouvez avec une vue de table.

Si vous avez une disposition de grille de base pour vos «parties» de vue de collection, vous pouvez également utiliser des cellules de tableau normales pour les gérer. Néanmoins, si vous n'avez pas besoin de la prise en charge d'iOS 5, vous devriez mieux utiliser les vues de collection.

Rivera
la source
1
Vous avez mis "traiter" entre guillemets, car vous ne pouvez PAS définir différentes mises en page par section CollectionView, non? Je n'ai pas trouvé d'option pour définir différentes mises en page pour différentes sections de vue de collection. Suis-je en train d'oublier quelque chose ou parlez-vous de répondre différemment à «layoutAttributesForItemAtIndexPath» pour différentes sections de ma propre sous-classe personnalisée de UICollectionViewLayout?
alex da franca
Oui -> Parlez-vous de répondre différemment aux layoutAttributesForItemAtIndexPathdifférentes sections de ma propre sous-classe personnalisée de UICollectionViewLayout?
Rivera
2
@Rivera, votre réponse est la plus raisonnable et semble juste correcte. J'ai lu cette suggestion à de nombreux endroits. Pourriez-vous également partager un lien vers un échantillon ou un test sur la façon d'accomplir cela ou au moins quelques pointeurs. TIA
thesummersign
3
Votre réponse suppose que vous partez de zéro et que vous n'avez pas déjà une vue de table complexe dans laquelle vous devez vous intégrer. La question posée spécifiquement sur la mise d'une vue de collection dans une vue de table. OMI votre réponse n'est pas une "réponse"
xaphod
2
C'est une mauvaise réponse. Avoir des vues de collection dans des vues de table est une chose tellement courante que presque toutes les applications le font.
crashoverride777
10

La réponse de Pablo Romeu ci-dessus ( https://stackoverflow.com/a/33364092/2704206 ) m'a énormément aidé avec mon problème. J'ai dû faire quelques choses différemment, cependant, pour que cela fonctionne pour mon problème. Tout d'abord, je n'ai pas eu à appeler layoutIfNeeded()aussi souvent. Je n'ai eu qu'à l'appeler collectionViewdans la systemLayoutSizeFittingfonction.

Deuxièmement, j'avais des contraintes de mise en page automatique sur ma vue de collection dans la cellule de vue de tableau pour lui donner un peu de remplissage. J'ai donc dû soustraire les marges de targetSize.widthdébut et de fin de la lors de la définition de la collectionView.framelargeur du. J'ai également dû ajouter les marges du haut et du bas à la CGSizehauteur de la valeur de retour .

Pour obtenir ces constantes de contrainte, j'avais la possibilité soit de créer des sorties aux contraintes, de coder en dur leurs constantes, soit de les rechercher par un identifiant. J'ai décidé d'utiliser la troisième option pour rendre ma classe de cellule de vue tableau personnalisée facilement réutilisable. En fin de compte, c'était tout ce dont j'avais besoin pour le faire fonctionner:

class CollectionTableViewCell: UITableViewCell {

    // MARK: -
    // MARK: Properties
    @IBOutlet weak var collectionView: UICollectionView! {
        didSet {
            collectionViewLayout?.estimatedItemSize = CGSize(width: 1, height: 1)
            selectionStyle = .none
        }
    }

    var collectionViewLayout: UICollectionViewFlowLayout? {
        return collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    }

    // MARK: -
    // MARK: UIView functions
    override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()

        let topConstraintConstant = contentView.constraint(byIdentifier: "topAnchor")?.constant ?? 0
        let bottomConstraintConstant = contentView.constraint(byIdentifier: "bottomAnchor")?.constant ?? 0
        let trailingConstraintConstant = contentView.constraint(byIdentifier: "trailingAnchor")?.constant ?? 0
        let leadingConstraintConstant = contentView.constraint(byIdentifier: "leadingAnchor")?.constant ?? 0

        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width - trailingConstraintConstant - leadingConstraintConstant, height: 1)

        let size = collectionView.collectionViewLayout.collectionViewContentSize
        let newSize = CGSize(width: size.width, height: size.height + topConstraintConstant + bottomConstraintConstant)
        return newSize
    }
}

En tant que fonction d'aide pour récupérer une contrainte par identifiant, j'ajoute l'extension suivante:

extension UIView {
    func constraint(byIdentifier identifier: String) -> NSLayoutConstraint? {
        return constraints.first(where: { $0.identifier == identifier })
    }
}

REMARQUE: vous devrez définir l'identifiant sur ces contraintes dans votre storyboard, ou partout où elles sont créées. À moins qu'ils n'aient une constante 0, cela n'a pas d'importance. De plus, comme dans la réponse de Pablo, vous devrez utiliser UICollectionViewFlowLayoutcomme mise en page pour votre vue de collection. Enfin, assurez-vous de lier l' collectionViewIBOutlet à votre storyboard.

Avec la cellule de vue de tableau personnalisée ci-dessus, je peux maintenant la sous-classer dans n'importe quelle autre cellule de vue de tableau qui a besoin d'une vue de collection et la faire implémenter les protocoles UICollectionViewDelegateFlowLayoutet UICollectionViewDataSource. J'espère que cela sera utile à quelqu'un d'autre!

jmad8
la source
5

J'ai lu toutes les réponses. Cela semble servir tous les cas.

override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()
        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width , height: 1)
        return collectionView.collectionViewLayout.collectionViewContentSize
}
SRP-Achiever
la source
3

Une alternative à la solution de Pablo Romeu est de personnaliser UICollectionView lui-même, plutôt que de faire le travail dans la cellule de vue de tableau.

Le problème sous-jacent est que, par défaut, une vue de collection n'a pas de taille intrinsèque et ne peut donc pas informer la disposition automatique des dimensions à utiliser. Vous pouvez remédier à cela en créant une sous-classe personnalisée qui renvoie une taille intrinsèque utile.

Créez une sous-classe de UICollectionView et remplacez les méthodes suivantes

override func intrinsicContentSize() -> CGSize {
    self.layoutIfNeeded()

    var size = super.contentSize
    if size.width == 0 || size.height == 0 {
        // return a default size
        size = CGSize(width: 600, height:44)
    }

    return size
 }

override func reloadData() {
    super.reloadData()
    self.layoutIfNeeded()
    self.invalidateIntrinsicContentSize()
}

(Vous devez également remplacer les méthodes associées: reloadSections, reloadItemsAtIndexPaths de la même manière que reloadData ())

L'appel de layoutIfNeeded force la vue de collection à recalculer la taille du contenu qui peut ensuite être utilisée comme nouvelle taille intrinsèque.

De plus, vous devez gérer explicitement les modifications de la taille de la vue (par exemple lors de la rotation de l'appareil) dans le contrôleur de vue de table

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    dispatch_async(dispatch_get_main_queue()) {
        self.tableView.reloadData()
    }
}
Vallée
la source
bro pourriez-vous s'il vous plaît aider mon problème stackoverflow.com/questions/44650058/… ?
Mai Phyu
3

J'étais confronté au même problème récemment et j'ai presque essayé toutes les solutions dans les réponses, certaines d'entre elles fonctionnaient et d'autres n'étaient pas ma principale préoccupation concernant l' approche @PabloRomeu est que si vous avez d'autres contenus dans la cellule (autre que la vue de la collection) vous devrez calculer leurs hauteurs et les hauteurs de leurs contraintes et retourner le résultat pour obtenir la bonne mise en page automatique et je n'aime pas calculer les choses manuellement dans mon code. Voici donc la solution qui a bien fonctionné pour moi sans faire de calculs manuels dans mon code.

dans la cellForRow:atIndexPathvue du tableau, je fais ce qui suit:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    //initialize the the collection view data source with the data
    cell.frame = CGRect.zero
    cell.layoutIfNeeded()
    return cell
}

Je pense que ce qui se passe ici, c'est que je force la cellule tableview à ajuster sa hauteur une fois que la hauteur de vue de la collection a été calculée. (après avoir fourni la date de collectionView à la source de données)

Abd Al-rhman Taher Badary
la source
2

Je mettrais une méthode statique sur la classe de vue de collection qui renverra une taille basée sur le contenu qu'elle aura. Utilisez ensuite cette méthode dans le heightForRowAtIndexPathpour renvoyer la taille appropriée.

Notez également que vous pouvez obtenir un comportement étrange lorsque vous intégrez ces types de viewControllers. Je l'ai fait une fois et j'ai eu des problèmes de mémoire étranges que je n'ai jamais résolus.

InkGolem
la source
Pour moi, j'essayais d'intégrer un contrôleur de vue de table dans des contrôleurs de vue de collection. Chaque fois qu'une cellule est réutilisée, elle a fini par se souvenir de certaines contraintes de mise en page automatique que je leur ai appliquées. C'était très délicat et c'était finalement une idée terrible. Je pense que je n'utiliserai qu'une seule vue de collection à la place.
fatuhoku
2

Peut-être que ma variante sera utile; J'ai décidé de cette tâche au cours des deux dernières heures. Je ne prétends pas que ce soit correct ou optimal à 100%, mais mes compétences sont encore très limitées et j'aimerais entendre les commentaires d'experts. Je vous remercie. Une note importante: cela fonctionne pour la table statique - c'est spécifié par mon travail actuel. Donc, tout ce que j'utilise est viewWillLayoutSubviews de tableView . Et un peu plus.

private var iconsCellHeight: CGFloat = 500 

func updateTable(table: UITableView, withDuration duration: NSTimeInterval) {
    UIView.animateWithDuration(duration, animations: { () -> Void in
        table.beginUpdates()
        table.endUpdates()
    })
}

override func viewWillLayoutSubviews() {
    if let iconsCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 1)) as? CategoryCardIconsCell {
        let collectionViewContentHeight = iconsCell.iconsCollectionView.contentSize.height
        if collectionViewContentHeight + 17 != iconsCellHeight {
            iconsCellHeight = collectionViewContentHeight + 17
            updateTable(tableView, withDuration: 0.2)
        }
    }
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    switch (indexPath.section, indexPath.row) {
        case ...
        case (1,0):
            return iconsCellHeight
        default:
            return tableView.rowHeight
    }
}
  1. Je sais que la collectionView est située dans la première ligne de la deuxième section;
  2. Soit la hauteur de la rangée est de 17 p. plus grand que sa hauteur de contenu;
  3. iconsCellHeight est un nombre aléatoire au démarrage du programme (je sais que sous forme de portrait, il doit être exactement 392, mais ce n'est pas important). Si le contenu de collectionView + 17 n'est pas égal à ce nombre, modifiez sa valeur. La prochaine fois dans cette situation, la condition donne FALSE;
  4. Après tout, mettez à jour le tableView. Dans mon cas, c'est la combinaison de deux opérations (pour une belle mise à jour des lignes étendues);
  5. Et bien sûr, dans le heightForRowAtIndexPath, ajoutez une ligne au code.
Ilya A. Shuvaloff
la source
2

L'approche la plus simple que j'ai proposée jusqu'à présent, Crédits à @igor réponse ci-dessus,

Dans votre classe tableviewcell, insérez simplement ceci

override func layoutSubviews() {
    self.collectionViewOutlet.constant = self.postPoll.collectionViewLayout.collectionViewContentSize.height
}

et bien sûr, changez la collectionviewoutlet avec votre prise dans la classe de la cellule

Osa
la source
1
La hauteur de la cellule ne calcule pas correctement
Nik Kov
2

Je reçois une idée de @Igor post et j'y consacre mon temps pour mon projet avec swift

Juste après ça dans ton

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    cell.frame = tableView.bounds
    cell.layoutIfNeeded()
    cell.collectionView.reloadData()
    cell.collectionView.heightAnchor.constraint(equalToConstant: cell.collectionView.collectionViewLayout.collectionViewContentSize.height)
    cell.layoutIfNeeded()
    return cell
}

Ajout: Si vous voyez votre UICollectionView saccadé lors du chargement de cellules.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {       
  //do dequeue stuff
  cell.layer.shouldRasterize = true
  cell.layer.rasterizationScale = UIScreen.main.scale
  return cell
}
Nazmul Hasan
la source
0

La solution de Pablo ne fonctionnait pas très bien pour moi, j'avais des effets visuels étranges (la collectionView ne s'ajustait pas correctement).

Ce qui fonctionnait, c'était d'ajuster la contrainte de hauteur de la collectionView (en tant que NSLayoutConstraint) à la collectionView contentSize pendant layoutSubviews(). Il s'agit de la méthode appelée lorsque la mise en page automatique est appliquée à la cellule.

// Constraint on the collectionView height in the storyboard. Priority set to 999.
@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!


// Method called by autolayout to layout the subviews (including the collectionView).
// This is triggered with 'layoutIfNeeded()', or by the viewController
// (happens between 'viewWillLayoutSubviews()' and 'viewDidLayoutSubviews()'.
override func layoutSubviews() {

    collectionViewHeightConstraint.constant = collectionView.contentSize.height
    super.layoutSubviews()
}

// Call `layoutIfNeeded()` when you update your UI from the model to trigger 'layoutSubviews()'
private func updateUI() {
    layoutIfNeeded()
}
Frédéric Adda
la source
-3

Dans votre UITableViewDelegate:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return ceil(itemCount/4.0f)*collectionViewCellHeight;
}

Remplacez itemCount et CollectionViewCellHeight par les valeurs réelles. Si vous avez un tableau de tableaux, itemCount peut être:

self.items[indexPath.row].count

Ou peu importe.

Martin
la source
Je pense que la question principale est de savoir comment calculer collectionViewCellHeight avant de le rendre.
thesummersign
-3

1.Créez une cellule factice.
Utilisez la méthode collectionViewContentSize sur UICollectionViewLayout de UICollectionView à l'aide des données actuelles.

Parag Shinde
la source
Cela devrait être la meilleure réponse ... puisqu'il n'y a aucune possibilité de définir la hauteur de la cellule avec 'uicollectionview' sans placer le contenu dans la cellule factice, obtenir la hauteur, puis la remettre dans la cellule appropriée
Bartłomiej Semańczyk
comment utiliser cette méthode?
xtrinch
Ajoutez un exemple.
Nik Kov
-5

Vous pouvez calculer la hauteur de la collection en fonction de ses propriétés comme itemSize, sectionInset, minimumLineSpacing, minimumInteritemSpacing, si votre collectionViewCella la frontière d'une règle.

sablib
la source