Open fedetrim opened 8 years ago
En realidad no está creando 1000 templateCell al principio de todo. Crea una sola pero después por cada ítem se llama a sizeForItemAtIndexPath y se calcula el tamaño de la celda configurada con el ítem correspondiente (ahí aplica las constraints). Esto genera un mínimo overhead al principio pero después no se vuelve a hacer el cálculo del tamaño.
¿Por qué decís que no es necesario hacer el override de sizeForItemAtIndexPath? ¿Cómo sabe el flowLayout que tamaño debería tener la celda?
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
guard let item = items?[indexPath.item],
templateCell = templateCell,
flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
else { return CGSizeZero }
templateCell.configure(item.text)
let numberOfColumns = UIApplication.sharedApplication().statusBarOrientation.isPortrait ? Constants.numberOfColumnsPortrait : Constants.numberOfColumnsLandscape
let sumOfSpaceBetweenCells = flowLayout.minimumInteritemSpacing * (numberOfColumns - 1)
let availableWidth = collectionView.frame.size.width - flowLayout.sectionInset.left - flowLayout.sectionInset.right - sumOfSpaceBetweenCells
let cellWidth = floor(availableWidth / numberOfColumns)
return templateCell.computeCellSizeWith(width: cellWidth)
}
Este método se llama una vez por cada ítem que tenga tu collection (fijate que te pide el size para determinado NSIndexPath
. Si tenés 1000 posibles NSIndexPath
, entonces se llama 1000 veces). Por lo tanto estás creando 1000 celdas, y por cada una, ejecutando lógica pesada para calcular tamaños.
Además, estas llamadas son consecutivas y se hacen por única vez, al cargar la collection (a menos que recargues algún ítem, por supuesto).
La siguiente línea...
self.flowLayout.estimatedItemSize = CGSize(width: 100, height: 100)
...le dice al layout de la collection que el contenido de tus celdas es dinámico, y en vez de pedirte el tamaño de cada una explícitamente en el collectionView( _, layout: _, sizeForItemAtIndexPath: _)
, directamente se lo pide al sistema de Auto Layout al tener que dibujar un ítem en particular.
Si usamos eso, tenemos que implementar en la celda el método:
override func preferredLayoutAttributesFittingAttributes(layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
layoutAttributes.bounds.size.height = systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
return layoutAttributes
}
Y después habría que ver como hacer para que en el estimatedItemSize pasarle el width correcto. Porque la idea era tener un layout a una columna en portrait y otro layout a dos columnas en landscape. Y esto lo lograba en sizeForItemAtIndexPath
haciendo:
let numberOfColumns = UIApplication.sharedApplication().statusBarOrientation.isPortrait ? Constants.numberOfColumnsPortrait : Constants.numberOfColumnsLandscape
let sumOfSpaceBetweenCells = flowLayout.minimumInteritemSpacing * (numberOfColumns - 1)
let availableWidth = collectionView.frame.size.width - flowLayout.sectionInset.left - flowLayout.sectionInset.right - sumOfSpaceBetweenCells
let cellWidth = floor(availableWidth / numberOfColumns)
No no, preferredLayoutAttributesFittingAttributes(_)
lo tenés que usar solamente si tu celda no está hecha con constraints.
Y con respecto a estimatedItemSize
, ahí podés tirar fruta. Esa info solamente se usa para estimar aproximadamente los largos de los scrolls.
Si no implemento preferredLayoutAttributesFittingAttributes no funciona.
Y necesito setearlo algo real al estimated, porque en preferredLayoutAttributesFittingAttributes el layoutAttributes.bounds.size es igual al estimated.
¿qué significa "no funciona"? ¿crashea?
Se queda infinitamente mostrando:
2016-09-06 18:16:09.293 CollectionViewComputedCellSizeExample[34218:771111] the behavior of the UICollectionViewFlowLayout is not defined because:
2016-09-06 18:16:09.294 CollectionViewComputedCellSizeExample[34218:771111] the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
2016-09-06 18:16:09.294 CollectionViewComputedCellSizeExample[34218:771111] Please check the values return by the delegate.
2016-09-06 18:16:09.295 CollectionViewComputedCellSizeExample[34218:771111] The relevant UICollectionViewFlowLayout instance is <UICollectionViewFlowLayout: 0x7ff5a8f5dfa0>, and it is attached to <UICollectionView: 0x7ff5a982e800; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x7ff5a8f5d010>; layer = <CALayer: 0x7ff5a8f59c90>; contentOffset: {0, -64}; contentSize: {375, 76.5}> collection view layout: <UICollectionViewFlowLayout: 0x7ff5a8f5dfa0>.
2016-09-06 18:16:09.295 CollectionViewComputedCellSizeExample[34218:771111] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
Cuando implemento preferredLayoutAttributesFittingAttributes como te mostré, se soluciona.
Entonces existe otro problema, pero te aseguro que esta es la posta. Tendría que verlo más en detalle para poder decirte exactamente qué está mal. Cuando me consiga un ratito me fijo y te aviso.
@ignaciovarela tuviste exito resolviendo el detalle?
Si la collection va a mostrar 1000 celdas, te estás creando 1000 templateCell al principio de todo, lo cual hace muy pesada la carga inicial de la pantalla. (Si lo probás con 1000 celdas vas a ver qué tarda algunos segundos en cargar el controller y mostrarlo)
Creo que la solución sería settear esto:
Y creo que una vez setteado eso, no es necesario overridear sizeForItem (no está chequeado, hay que probarlo)