L'un de nos écrans d'application nous oblige à placer un UICollectionView
intérieur d' un fichier UITableViewCell
. Cela UICollectionView
aura 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 UITableViewCell
fonction de la hauteur du UICollectionView
.
Quelqu'un peut-il donner des astuces ou des conseils sur la façon d'accomplir cela?
ios
uitableview
uicollectionview
Homme de l'ombre
la source
la source
UITableViewCell
tableau est-elle différente de sa vue de table réelle? Avez-vous besoin d'un défilement vertical sur leUICollectionView
et leUITableView
Réponses:
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:
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":
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).
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.TableViewController
N'oubliez pas d'activer le système de disposition automatique pour les cellules tableView sur votre TableViewController :
CRÉDIT: @rbarbera a aidé à résoudre ce problème
la source
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.systemLayoutSizeFittingSize
, j'ai rencontré un problème rapidement lors du rechargement de la cellule, les applications semblent rester bloquées après leself.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.systemLayoutSizeFitting
, inversez l'ordre de ce qui est affiché dans la réponse actuellement, de sorte que le premiercollectionView.layoutIfNeeded()
s'exécute, puiscollectionView.frame = CGRect.init(origin: .zero, size: CGSize.init(width: targetSize.width, height: 1))
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ùUICollectionView
est placée. Laisse, son nom seracollectionView
Étape 2. Ajoutez IB pour la
UICollectionView
contrainte de hauteur et créez également une sortieUITableViewCell subclass
. Laissez, son nom seracollectionViewHeight
.Étape 3. Dans
tableView:cellForRowAtIndexPath:
ajouter du code:la source
collectionView
tous les côtésUITableViewCell
et ensembletableView.estimatedRowHeight = 44;
ettableView.rowHeight = UITableViewAutomaticDimension;
Les vues de table et les vues de collection sont des
UIScrollView
sous - 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.
la source
layoutAttributesForItemAtIndexPath
différentes sections de ma propre sous-classe personnalisée deUICollectionViewLayout
?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'appelercollectionView
dans lasystemLayoutSizeFitting
fonction.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.width
début et de fin de la lors de la définition de lacollectionView.frame
largeur du. J'ai également dû ajouter les marges du haut et du bas à laCGSize
hauteur 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:
En tant que fonction d'aide pour récupérer une contrainte par identifiant, j'ajoute l'extension suivante:
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
UICollectionViewFlowLayout
comme mise en page pour votre vue de collection. Enfin, assurez-vous de lier l'collectionView
IBOutlet à 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
UICollectionViewDelegateFlowLayout
etUICollectionViewDataSource
. J'espère que cela sera utile à quelqu'un d'autre!la source
J'ai lu toutes les réponses. Cela semble servir tous les cas.
la source
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
(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
la source
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:atIndexPath
vue du tableau, je fais ce qui suit: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)
la source
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
heightForRowAtIndexPath
pour 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.
la source
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.
la source
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
et bien sûr, changez la collectionviewoutlet avec votre prise dans la classe de la cellule
la source
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
Ajout: Si vous voyez votre UICollectionView saccadé lors du chargement de cellules.
la source
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.la source
Dans votre UITableViewDelegate:
Remplacez itemCount et CollectionViewCellHeight par les valeurs réelles. Si vous avez un tableau de tableaux, itemCount peut être:
Ou peu importe.
la source
collectionViewCellHeight
avant de le rendre.1.Créez une cellule factice.
Utilisez la méthode collectionViewContentSize sur UICollectionViewLayout de UICollectionView à l'aide des données actuelles.
la source
Vous pouvez calculer la hauteur de la collection en fonction de ses propriétés comme
itemSize
,sectionInset
,minimumLineSpacing
,minimumInteritemSpacing
, si votrecollectionViewCell
a la frontière d'une règle.la source