uicollectionviewflowlayoutautomaticsize uicollectionviewdelegateflowlayout systemlayoutsizefitting automatic ios objective-c uicollectionview nslayoutconstraint

ios - uicollectionviewdelegateflowlayout - Altura de autosize UICollectionView



uicollectionview resize cell (7)

¿Cómo cambio correctamente el tamaño de UICollectionView para que muestre completamente sus contenidos? He intentado muchas cosas, incluida la configuración de su marco, la invocación de reloadData y la invalidación del diseño:

self.collectionView.contentSize = CGSizeMake(300, 2000); self.collectionView.frame = CGRectMake(0, 0, 300, 2000); [self.collectionView reloadData]; [self.collectionView.collectionViewLayout invalidateLayout];

pero nada de esto tiene ningún efecto. Después de presionar el botón todavía veo la vista inicial, así:

Tengo un pequeño programa de demostración en el que tengo una fuente de datos que produce 100 elementos. En Interface Builder, inicialmente configuré el tamaño de UICollectionView en un valor pequeño para que no quepan todos los elementos, después de eso presiono un botón luego de ejecutar el código anterior. Espero que UICollectionView ahora muestre todos los elementos, pero no es así.

EDITAR: El programa de demostración se puede encontrar en https://github.com/mjdemilliano/TestUICollectionView .

EDIT2: He observado que la actualización del cuadro se pierde en algún momento, porque si presiono el botón nuevamente, el cuadro actual vuelve al valor anterior. Después de agregar algunas instrucciones de registro en el controlador de eventos del botón, el resultado del registro es:

before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190} update button pressed after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000} before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190} update button pressed after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}

No entiendo por qué no se guarda el cambio de marco, qué lo está cambiando.

En algún momento reemplazaré los valores codificados por valores obtenidos del diseño de flujo, pero quería descartarlo y mantener mi ejemplo lo más simple posible.

Contexto: lo que quiero hacer eventualmente es lo siguiente: tengo una vista desplazable con varios controles, como etiquetas e imágenes, y una vista de colección con contenido dinámico. Quiero desplazar todo eso, no solo la vista de colección, por lo tanto, no estoy utilizando las propias funciones de desplazamiento de la vista de colección, que funcionan bien.


Aquí está mi implementación en Swift 3:

override func sizeThatFits(_ size: CGSize) -> CGSize { if (self.superview != nil) { self.superview?.layoutIfNeeded() } return collectionView.contentSize }


Aquí hay una manera de enlazar la altura de CollectionView a través de su tamaño intrínseco. Lo usé para dimensionar correctamente una vista de colección dentro de una celda TableView (con altura de celda dinámica). y funciona perfectamente

Primero, agregue esto a su subclase UICollectionView:

override var intrinsicContentSize: CGSize { get { return self.contentSize } }

A continuación, llame a layout IfNeeded () después de volver a cargar los datos:

reloadData() layoutIfNeeded()


El método más simple que encontré es pverride sizeThatFits: methods as is:

- (CGSize)sizeThatFits:(CGSize)size { if( self.superview ) [self.superview layoutIfNeeded]; // to force evaluate the real layout return self.collectionViewLayout.collectionViewContentSize; }


Finalmente resolví esto solucionando todos los problemas de Auto Layout, arreglando el alto de la vista de colección usando una restricción. Entonces, cada vez que sé que el contenido ha cambiado, actualizo el valor de la restricción usando el valor collectionView.contentSize.height :

self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height;

Luego, la vista de colección se redimensiona correctamente y se comporta bien dentro de la vista de desplazamiento general. He actualizado el proyecto de prueba de GitHub con mis cambios.

Para mí, hacer esto actualizando la restricción manualmente en lugar de poder decirle a iOS: "hacer que la altura del marco de la vista de la colección sea tan grande como sea necesario" no me parece correcto, pero es lo mejor que he encontrado hasta ahora . Por favor publique una mejor respuesta si tiene una.


Para mí es aún más simple, creo

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { //add following code line after adding cells, before Return ........... ......... scrollView.contentSize = = collectionView.contentSize; //now scrollView size is equal to collectionView size. No matter how small or big it is. return cell; }


Puedes probar mi clase personalizada AGCollectionView

  • Asigne una restricción de altura de collectionView utilizando un guión gráfico o programáticamente.

- Asigna esta clase a tu UICollectionView .

class AGCollectionView: UICollectionView { fileprivate var heightConstraint: NSLayoutConstraint! override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) { super.init(frame: frame, collectionViewLayout: layout) self.associateConstraints() } required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.associateConstraints() } override open func layoutSubviews() { super.layoutSubviews() if self.heightConstraint != nil { self.heightConstraint.constant = floor(self.contentSize.height) } else{ self.sizeToFit() print("Set a heightConstraint set size to fit content") } } func associateConstraints() { // iterate through height constraints and identify for constraint: NSLayoutConstraint in constraints { if constraint.firstAttribute == .height { if constraint.relation == .equal { heightConstraint = constraint } } } } }


UICollectionViewFlowLayout *flowLayout; flowLayout = [[UICollectionViewFlowLayout alloc]init]; [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical]; [flowLayout setMinimumInteritemSpacing:0.0f]; [flowLayout setMinimumLineSpacing:0.0f]; [self.collectionView setPagingEnabled:NO]; [flowLayout setItemSize:CGSizeMake(322.0, 148.0)]; //important to leave no white space between the images [self.collectionView setCollectionViewLayout:flowLayout];

Descubrí que el diseño automático en el guión gráfico no ayuda demasiado. Una configuración correcta para UICollectionViewFlowLayout para su collectionView es la verdadera ayuda. Si ajusta el tamaño del elemento con setItemSize, puede obtener el resultado que desea.