Estoy usando un UICollectionView en mi proyecto, donde hay varias celdas de diferentes anchos en una línea. Según: https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html
extiende las celdas a lo largo de la línea con el mismo relleno. Esto sucede como se esperaba, excepto que quiero justificarlos a la izquierda y codificar un ancho de relleno.
Supongo que necesito subclasificar UICollectionViewFlowLayout, sin embargo, después de leer algunos de los tutoriales, etc.en línea, parece que no entiendo cómo funciona esto.
Respuestas:
Las otras soluciones en este hilo no funcionan correctamente, cuando la línea está compuesta por solo 1 artículo o son demasiado complicadas.
Basado en el ejemplo dado por Ryan, cambié el código para detectar una nueva línea inspeccionando la posición Y del nuevo elemento. Muy simple y de ejecución rápida.
Rápido:
Si desea que las vistas complementarias mantengan su tamaño, agregue lo siguiente en la parte superior del cierre de la
forEach
convocatoria:C objetivo:
fuente
let attributes = super.layoutAttributesForElementsInRect(rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes }
Hay muchas grandes ideas incluidas en las respuestas a esta pregunta. Sin embargo, la mayoría tiene algunos inconvenientes:
La mayoría de las soluciones solo anulan la
layoutAttributesForElements(in rect: CGRect)
función. No anulanlayoutAttributesForItem(at indexPath: IndexPath)
. Esto es un problema porque la vista de colección llama periódicamente a la última función para recuperar los atributos de diseño para una ruta de índice en particular. Si no devuelve los atributos adecuados de esa función, es probable que se encuentre con todo tipo de errores visuales, por ejemplo, durante la inserción y eliminación de animaciones de celdas o al usar celdas de tamaño propio configurando el diseño de la vista de colecciónestimatedItemSize
. Los documentos de Apple dicen:Muchas soluciones también hacen suposiciones sobre el
rect
parámetro que se pasa a lalayoutAttributesForElements(in rect: CGRect)
función. Por ejemplo, muchos se basan en la suposición de querect
siempre comienza al principio de una nueva línea, lo que no es necesariamente el caso.Entonces en otras palabras:
La mayoría de las soluciones sugeridas en esta página funcionan para algunas aplicaciones específicas, pero no funcionan como se esperaba en todas las situaciones.
AlignedCollectionViewFlowLayout
Para abordar estos problemas, he creado una
UICollectionViewFlowLayout
subclase que sigue una idea similar a la sugerida por Matt y Chris Wagner en sus respuestas a una pregunta similar. Puede alinear las celdas⬅︎ izquierda :
o ➡︎ bien :
y además ofrece opciones para verticalmente alinear las celdas en sus respectivas filas (en caso de que varíen en altura).
Simplemente puede descargarlo aquí:
https://github.com/mischa-hildebrand/AlignedCollectionViewFlowLayout
El uso es sencillo y se explica en el archivo README. Básicamente, crea una instancia de
AlignedCollectionViewFlowLayout
, especifica la alineación deseada y la asigna a lacollectionViewLayout
propiedad de la vista de su colección :(También está disponible en Cocoapods ).
Cómo funciona (para celdas alineadas a la izquierda):
El concepto aquí es depender únicamente de la
layoutAttributesForItem(at indexPath: IndexPath)
función . En ellayoutAttributesForElements(in rect: CGRect)
, simplemente obtenemos las rutas de índice de todas las celdas dentro derect
y luego llamamos a la primera función para cada ruta de índice para recuperar los marcos correctos:(La
copy()
función simplemente crea una copia profunda de todos los atributos de diseño en la matriz. Puede buscar en el código fuente para su implementación).Así que ahora lo único que tenemos que hacer es implementar la
layoutAttributesForItem(at indexPath: IndexPath)
función correctamente. La superclaseUICollectionViewFlowLayout
ya pone el número correcto de celdas en cada línea, por lo que solo tenemos que moverlas a la izquierda dentro de su fila respectiva. La dificultad radica en calcular la cantidad de espacio que necesitamos para desplazar cada celda hacia la izquierda.Como queremos tener un espaciado fijo entre las celdas, la idea central es simplemente asumir que la celda anterior (la celda a la izquierda de la celda que se presenta actualmente) ya está colocada correctamente. Entonces solo tenemos que agregar el espaciado de celda al
maxX
valor del marco de la celda anterior y ese es elorigin.x
valor para el marco de la celda actual.Ahora solo necesitamos saber cuándo hemos llegado al comienzo de una línea, para no alinear una celda al lado de una celda en la línea anterior. (Esto no solo daría como resultado un diseño incorrecto, sino que también sería extremadamente lento). Por lo tanto, necesitamos tener un ancla de recursividad. El enfoque que utilizo para encontrar ese ancla de recursividad es el siguiente:
Para saber si la celda en el índice i está en la misma línea que la celda con el índice i-1 ...
... "dibujo" un rectángulo alrededor de la celda actual y lo estiro sobre el ancho de toda la vista de la colección. Como los
UICollectionViewFlowLayout
centros de todas las celdas verticalmente, cada celda en la misma línea debe cruzarse con este rectángulo.Por lo tanto, simplemente verifico si la celda con índice i-1 se cruza con este rectángulo de línea creado a partir de la celda con índice i .
Si se cruza, la celda con el índice i no es la celda más a la izquierda de la línea.
→ Obtenga el marco de la celda anterior (con el índice i − 1 ) y mueva la celda actual a su lado.
Si no se cruza, la celda con el índice i es la celda más a la izquierda de la línea.
→ Mueva la celda al borde izquierdo de la vista de colección (sin cambiar su posición vertical).
No publicaré la implementación real de la
layoutAttributesForItem(at indexPath: IndexPath)
función aquí porque creo que la parte más importante es comprender la idea y siempre puedes verificar mi implementación en el código fuente . (Es un poco más complicado de lo que se explica aquí porque también permito la.right
alineación y varias opciones de alineación vertical. Sin embargo, sigue la misma idea).Vaya, supongo que esta es la respuesta más larga que he escrito en Stackoverflow. Espero que esto ayude. 😉
fuente
Con Swift 4.1 e iOS 11, según sus necesidades, puede elegir una de las 2 siguientes implementaciones completas para solucionar su problema.
# 1. Alinear a la izquierda el tamaño automático de
UICollectionViewCell
sLa aplicación siguiente muestra cómo utilizar
UICollectionViewLayout
'slayoutAttributesForElements(in:)
,UICollectionViewFlowLayout
' sestimatedItemSize
, yUILabel
'spreferredMaxLayoutWidth
con el fin de alinear las células de tamaño automático izquierda en unaUICollectionView
:CollectionViewController.swift
FlowLayout.swift
CollectionViewCell.swift
Resultado Esperado:
# 2. Alinear a la izquierda
UICollectionViewCell
s con tamaño fijoLa implementación de abajo muestra cómo utilizar
UICollectionViewLayout
'slayoutAttributesForElements(in:)
yUICollectionViewFlowLayout
sitemSize
con el fin de alinear a la izquierda células con tamaño predefinido en unaUICollectionView
:CollectionViewController.swift
FlowLayout.swift
CollectionViewCell.swift
Resultado Esperado:
fuente
10
un número arbitrario?La solución simple en 2019
Esta es una de esas preguntas deprimentes en las que las cosas han cambiado mucho a lo largo de los años. Ahora es fácil.
Básicamente, solo haces esto:
Todo lo que necesita ahora es el código repetitivo:
Simplemente copie y pegue eso en un
UICollectionViewFlowLayout
, ya está.Solución de trabajo completa para copiar y pegar:
Esto es todo:
Y finalmente...
¡Dale las gracias a @AlexShubin, quien primero aclaró esto!
fuente
La pregunta se ha planteado un tiempo pero no hay respuesta y es una buena pregunta. La respuesta es anular un método en la subclase UICollectionViewFlowLayout:
Según lo recomendado por Apple, obtienes los atributos de diseño de super e iteras sobre ellos. Si es el primero en la fila (definido por su origen.x está en el margen izquierdo), déjelo solo y restablezca la x a cero. Luego, para la primera celda y cada celda, agrega el ancho de esa celda más un margen. Esto pasa al siguiente elemento del ciclo. Si no es el primer elemento, establece su origin.x en el margen calculado en ejecución y agrega nuevos elementos a la matriz.
fuente
attribute.center.x == self.collectionView?.bounds.midX
leftMargin
con elif (attributes.frame.origin.x == self.sectionInset.left) {
cheque. Esto supone que el diseño predeterminado ha alineado la celda de la nueva fila para alinearla consectionInset.left
. Si este no es el caso, resultaría el comportamiento que describe. Insertaría un punto de interrupción dentro del bucle y verificaría ambos lados para la celda de la segunda fila justo antes de la comparación. La mejor de las suertes.Tuve el mismo problema. Prueba Cocoapod UICollectionViewLeftAlignedLayout . Solo inclúyalo en su proyecto e inicialícelo así:
fuente
Basándome en la respuesta de Michael Sand , creé una
UICollectionViewFlowLayout
biblioteca de subclases para hacer la justificación horizontal izquierda, derecha o completa (básicamente la predeterminada); también le permite establecer la distancia absoluta entre cada celda. También planeo agregarle justificación central horizontal y justificación vertical.https://github.com/eroth/ERJustifiedFlowLayout
fuente
Aquí está la respuesta original en Swift. Todavía funciona muy bien en su mayoría.
Excepción: tamaño automático de celdas
Lamentablemente, hay una gran excepción. Si estás usando
UICollectionViewFlowLayout
'sestimatedItemSize
. InternamenteUICollectionViewFlowLayout
está cambiando un poco las cosas. No lo he rastreado por completo, pero está claro que está llamando a otros métodos después de laslayoutAttributesForElementsInRect
celdas de tamaño propio. Por mi prueba y error, descubrí que parece llamarlayoutAttributesForItemAtIndexPath
a cada celda individualmente durante el tamaño automático con más frecuencia. Esta actualizaciónLeftAlignedFlowLayout
funciona muy bien conestimatedItemSize
. También funciona con celdas de tamaño estático, sin embargo, las llamadas de diseño adicionales me llevan a usar la respuesta original en cualquier momento que no necesite celdas de tamaño automático.fuente
En rápido. Según la respuesta de Michaels
fuente
Basado en todas las respuestas, cambio un poco y me funciona bien
fuente
Si alguno de ustedes tiene un problema, algunas de las celdas que están a la derecha de la vista de colección exceden los límites de la vista de colección . Entonces por favor use esto -
Utilice INT en lugar de comparar valores CGFloat .
fuente
Basado en las respuestas aquí, pero se corrigieron fallas y problemas de alineación cuando la vista de su colección también tiene encabezados o pies de página. Alinear solo celdas a la izquierda:
fuente
Gracias por la respuesta de Michael Sand . Lo modifiqué a una solución de varias filas (la misma alineación superior y de cada fila) que es Alineación izquierda, con un espaciado uniforme para cada elemento.
fuente
Aquí está mi viaje para encontrar el mejor código que funcione con Swift 5. He unido un par de respuestas de este hilo y algunos otros hilos para resolver advertencias y problemas que enfrenté. Recibí una advertencia y un comportamiento anormal al desplazarme por la vista de mi colección. La consola imprime lo siguiente:
Otro problema al que me enfrenté es que algunas celdas largas se recortan en el lado derecho de la pantalla. Además, estaba configurando las inserciones de sección y el mínimoInteritemSpacing en las funciones de delegado que dieron como resultado que los valores no se reflejaran en la clase personalizada. La solución para eso fue establecer esos atributos en una instancia del diseño antes de aplicarlo a la vista de mi colección.
Así es como usé el diseño para la vista de mi colección:
Aquí está la clase de diseño de flujo
fuente
El problema con UICollectionView es que intenta ajustar automáticamente las celdas en el área disponible. He hecho esto definiendo primero el número de filas y columnas y luego definiendo el tamaño de celda para esa fila y columna
1) Para definir secciones (filas) de mi UICollectionView:
2) Para definir el número de elementos en una sección. Puede definir un número diferente de elementos para cada sección. puede obtener el número de sección usando el parámetro 'sección'.
3) Definir el tamaño de celda para cada sección y fila por separado. Puede obtener el número de sección y el número de fila utilizando el parámetro 'indexPath', es decir,
[indexPath section]
para el número de sección y el número[indexPath row]
de fila.4) Luego, puede mostrar sus celdas en filas y secciones usando:
NOTA: En UICollectionView
fuente
La respuesta de Mike Sand es buena, pero había experimentado algunos problemas con este código (como una celda larga recortada). Y nuevo código:
fuente
Editó la respuesta de Ángel García Olloqui al respeto
minimumInteritemSpacing
de los delegadoscollectionView(_:layout:minimumInteritemSpacingForSectionAt:)
, si la implementa.fuente
El código anterior funciona para mí. Me gustaría compartir el código Swift 3.0 respectivo.
fuente