¿Cómo centrar horizontalmente las celdas UICollectionView?

123

He investigado un poco, pero no pude encontrar ningún ejemplo de código sobre cómo centrar celdas en una UICollectionView horizontalmente.

en lugar de que la primera celda sea así X00 , quiero que sea así 0X0 . ¿Hay alguna forma de lograr esto?

EDITAR:

para visualizar lo que quiero:

ingrese la descripción de la imagen aquí

Necesito que se parezca a la versión B cuando solo hay un elemento en CollectionView. Cuando obtuve más de un elemento, debería ser como la versión A pero con más elementos.

En este momento, se parece a la Versión A cuando tengo solo 1 elemento, y me pregunto cómo puedo hacer que se parezca a B.

¡Gracias por la ayuda!

RaptoX
fuente
¿No es más fácil dejar que la celda se ajuste al ancho de la vista de colección y luego centrar la vista de colección dentro de su padre?
Arthur Gevorkyan
sí, hay al menos dos formas de hacer esto, primero (rápido) es hacer el ancho de celda de toda la pantalla y centrar su vista secundaria. segundo (derecho) implementar diseño de vista de colección personalizada
sage444
Eventualmente habrá más celdas provenientes del back-end, llenar el ancho completo no sería una buena idea
RaptoX
aumentar el ancho es suficiente para establecer en el centro
Kishore Kumar

Respuestas:

227

No es una buena idea usar una biblioteca, si su propósito es solo esto, es decir, alinear al centro.

Mejor puede hacer este cálculo simple en su función collectionViewLayout.

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    let totalCellWidth = CellWidth * CellCount
    let totalSpacingWidth = CellSpacing * (CellCount - 1)

    let leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
Darshan Patel.
fuente
2
@ DarshanPatel. Gracias a muchas de las respuestas, implementé esto y las filas llegaron al centro como debería, pero ahora el problema es que no puedo desplazarme al primer elemento. Cuando intento desplazarme al primer elemento, me devuelve a los UIEdgeInsets modificados. Puedes ver mi aplicación de demostración github.com/anirudha-music/CollectionViewCenter
Anirudha Mahale
55
En Swift 3, la firma del nuevo método es collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int).
Kamchatka
1
¿Cómo puede tomar el ancho de celda? ¿Es posible a través del método cellForItemAt? Lo intenté y me devolvió nulo ... el ancho de celda para mí cambia según el tamaño de la pantalla ... @DarshanPatel.
Chris
10
@DarshanPatel. Su respuesta a veces puede producir un valor negativo en dispositivos más pequeños. Considere usar un control máximo de su leftInsetvalor de la siguiente manera:let leftInset = max(0.0, (self.collectionView.bounds.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2)
Rhuari Glen el
3
Si no está subclasificando UICollectionViewController, asegúrese de que su clase cumpla con UICollectionViewDelegateFlowLayout, de lo contrario no funcionará
Saeed Ir
59

Swift 5.1

func centerItemsInCollectionView(cellWidth: Double, numberOfItems: Double, spaceBetweenCell: Double, collectionView: UICollectionView) -> UIEdgeInsets {
    let totalWidth = cellWidth * numberOfItems
    let totalSpacingWidth = spaceBetweenCell * (numberOfItems - 1)
    let leftInset = (collectionView.frame.width - CGFloat(totalWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset
    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}

Swift 4.2

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
    let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

    let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)

}

Swift 3

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

        let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
        let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

        let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
        let rightInset = leftInset

        return UIEdgeInsetsMake(0, leftInset, 0, rightInset)

    }

no olvides agregar el protocolo

UICollectionViewDelegateFlowLayout
Ahmed Safadi
fuente
restricción tal vez @ashForIos
Ahmed Safadi
Su respuesta funciona bien cuando hay celdas que se ajustan en collectionView cuando el recuento de celdas aumenta, las celdas están en el centro y no puede desplazarse a las primeras celdas ni a las últimas.
NickCoder
2
@Vitalii 80 ancho medio de celda, y 10 el espacio entre celdas, si lees el nombre de la variable entenderías lo que significa: P
Ahmed Safadi
La solución Swift 4.2 es más fácil, ¡GRACIAS! Solo asegúrese de establecer el "80" en el ancho real de su objeto de celda.
John Pitts
25

Prueba esto para Swift 4

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth : CGFloat = 165.0

        let numberOfCells = floor(self.view.frame.size.width / cellWidth)
        let edgeInsets = (self.view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsetsMake(15, edgeInsets, 0, edgeInsets)
    }

Agregue su cellWidth en su lugar 165.0

Oscar Castellon
fuente
1
Esta es la mejor respuesta. Con las matemáticas más simples. funciona con cualquier número de filas y columnas
rickrvo
20

Utilizo KTCenterFlowLayout para esto, y funciona muy bien. Es una subclase personalizada UICollectionViewFlowLayoutque centra las celdas como desee. (Nota: esto no es algo trivial para resolver publicando algo de código, ¡por eso me estoy vinculando a un proyecto de GitHub!)

TwoStraws
fuente
No se pudo hacer que funcione desde IB. Esta biblioteca funcionó como un encanto para mí. ¡Acabo de instalar el pod y cambié la clase de diseño en IB!
tagirkaZ
15

Una versión del objetivo C de la respuesta de Darshan Patel :

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    CGFloat totalCellWidth = kItemWidth * self.dataArray.count;
    CGFloat totalSpacingWidth = kSpacing * (((float)self.dataArray.count - 1) < 0 ? 0 :self.dataArray.count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}
Persona maravillosa
fuente
Gracias. Está funcionando bien con una sola fila. pero creando un problema en varias filas. No puedo agregar la URL aquí para mostrar la captura de pantalla. . pero puedes agregar "yynoalzg" en una pequeña URL. Tendrás idea. La sección de oro tiene 4 registros. 4to debe estar en nueva línea. . pero después de este método se muestra así ... avíseme si tiene alguna idea.
Hitarth
6

Modificando ligeramente la respuesta de @Safad Funy, esto es lo que funcionó para mí en la última versión de Swift e iOS. En este caso, quería que el ancho de las celdas fuera un tercio del tamaño de la vista de colección.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

  let totalCellWidth = Int(collectionView.layer.frame.size.width) / 3 * collectionView.numberOfItems(inSection: 0)
  let totalSpacingWidth = (collectionView.numberOfItems(inSection: 0) - 1)

  let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
  let rightInset = leftInset

  return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
MXV
fuente
2
Esto funcionó especialmente para mí, cuando solo hay una celda.
Dasoga
6

Puede usar esta extensión (Swift 4).

Puede centrar celdas con si collectionViewtiene layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize.

Funciona con cualquier tamaño de celda y funciona perfectamente cuando scrollDirection = .horizontal

public extension UICollectionView {
    func centerContentHorizontalyByInsetIfNeeded(minimumInset: UIEdgeInsets) {
        guard let layout = collectionViewLayout as? UICollectionViewFlowLayout,
            layout.scrollDirection == .horizontal else {
                assertionFailure("\(#function): layout.scrollDirection != .horizontal")
                return
        }

        if layout.collectionViewContentSize.width > frame.size.width {
            contentInset = minimumInset
        } else {
            contentInset = UIEdgeInsets(top: minimumInset.top,
                                        left: (frame.size.width - layout.collectionViewContentSize.width) / 2,
                                        bottom: minimumInset.bottom,
                                        right: 0)
        }
    }
}


final class Foo: UIViewController {
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.centerContentHorizontalyByInsetIfNeeded(minimumInset: yourDefaultInset)
    }
}

Espero que sea de ayuda!

S. Matsepura
fuente
1
Obteniendo error: Tema 1: EXC_BAD_ACCESS (código = 2, dirección = 0x118ffde58)
atulkhatri
4

Swift 4.2 (horizontal y verticalmente). ¡Es una pequeña actualización del código de Pink Panther y muchas gracias!


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellHieght: CGFloat = flowLayout.itemSize.height
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    var collectionHeight = collectionView.frame.size.height
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
        collectionHeight -= collectionView.safeAreaInsets.top + collectionView.safeAreaInsets.bottom
    }
    let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
    let totalHieght = cellHieght * cellCount + cellSpacing * (cellCount - 1)
    if totalWidth <= collectionWidth {
        let edgeInsetWidth = (collectionWidth - totalWidth) / 2

        print(edgeInsetWidth, edgeInsetWidth)
        return UIEdgeInsets(top: 5, left: edgeInsetWidth, bottom: flowLayout.sectionInset.top, right: edgeInsetWidth)
    } else {
        let edgeInsetHieght = (collectionHeight - totalHieght) / 2
        print(edgeInsetHieght, edgeInsetHieght)
        return UIEdgeInsets(top: edgeInsetHieght, left: flowLayout.sectionInset.top, bottom: edgeInsetHieght, right: flowLayout.sectionInset.top)

    }
}

Asegúrese de que su clase cumpla con el protocolo UICollectionViewDelegateFlowLayout

EVGENIY DANILOV
fuente
Realmente tu código funciona muy bien para mí, gracias Amigo; )
steveSarsawa
4

Aquí está la versión más nueva para Swift 5 que también funciona bien cuando las celdas son más de una fila:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    var cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    var totalWidth: CGFloat
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    repeat {
        totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
        cellCount -= 1
    } while totalWidth >= collectionWidth

    if (totalWidth > 0) {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsets.init(top: flowLayout.sectionInset.top, left: edgeInset, bottom: flowLayout.sectionInset.bottom, right: edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}

Asegúrese de que su clase cumpla con el UICollectionViewDelegateFlowLayoutprotocolo.

Saeed Ir
fuente
3

Swift 4

extension ViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

        let cellWidth: CGFloat = 170.0 // Your cell width

        let numberOfCells = floor(view.frame.size.width / cellWidth)
        let edgeInsets = (view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets)
    }

 }
Haroldo Gondim
fuente
2

Para las personas que solo desean agregar un relleno ( arriba, izquierda, abajo, derecha ):

Agregar el protocolo UICollectionViewDelegateFlowLayout

Este ejemplo muestra un relleno izquierdo y derecho con 40.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {        
    return UIEdgeInsetsMake(0, 40, 0, 40)
}
escalera de cadena
fuente
2

SWIFT 4.2

private lazy var contentView: UICollectionView = {
        let layoutView: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
            layoutView.scrollDirection = .horizontal
            layoutView.minimumInteritemSpacing = 0
            layoutView.minimumLineSpacing = 5

        let collectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: layoutView)
            collectionView.dataSource = self
            collectionView.delegate = self
            collectionView.showsHorizontalScrollIndicator = false
            collectionView.isPagingEnabled = true
            collectionView.registerCell(Cell.self)
            collectionView.backgroundColor = .clear
            collectionView.translatesAutoresizingMaskIntoConstraints = false
        return collectionView
    }()

//

extension CustomCollectionView: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        return CGSize(width: collectionView.frame.width*4/5, height: collectionView.frame.height)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth : CGFloat = collectionView.frame.width*4/5

        let numberOfCells = floor(collectionView.frame.width / cellWidth)
        let edgeInsets = (collectionView.frame.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: edgeInsets)
    }
}
iEvgen Podkorytov
fuente
1

Puedes probar mi solución, funciona bien,

func refreshCollectionView(_ count: Int) {
    let collectionViewHeight = collectionView.bounds.height
    let collectionViewWidth = collectionView.bounds.width
    let numberOfItemsThatCanInCollectionView = Int(collectionViewWidth / collectionViewHeight)
    if numberOfItemsThatCanInCollectionView > count {
        let totalCellWidth = collectionViewHeight * CGFloat(count)
        let totalSpacingWidth: CGFloat = CGFloat(count) * (CGFloat(count) - 1)
        // leftInset, rightInset are the global variables which I am passing to the below function
        leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2;
        rightInset = -leftInset
    } else {
        leftInset = 0.0
        rightInset = -collectionViewHeight
    }
    collectionView.reloadData()
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
Anirudha Mahale
fuente
1

La respuesta aceptada es la correcta, pero si su totalCellWidthes menor que la de CollectionView's' width, pero solo para protegerse de esto, puede hacer lo siguiente.

if (leftInset > 0) {
     return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
  } else {
     return UIEdgeInsetsMake(0, 10, 0, 10)
}
azwethinkweiz
fuente
1

Este código debe centrar la vista de recopilación horizontal incluso en Swift 4.0 sin ninguna modificación:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
    if totalWidth <= collectionWidth {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsetsMake(flowLayout.sectionInset.top, edgeInset, flowLayout.sectionInset.bottom, edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}

Asegúrese de que su clase cumpla con el UICollectionViewDelegateFlowLayoutprotocolo

Saeed Ir
fuente
0

Terminé tomando un enfoque completamente diferente aquí, que creo que vale la pena mencionar.

Establezco una restricción en mi vista de colección para que esté alineada horizontalmente en el centro. Luego establecí otra restricción que especifica el ancho. Creé una salida para la restricción de ancho dentro de mi viewController que contiene la vista de colección. Luego, cuando se cambia mi fuente de datos y estoy actualizando la vista de recopilación, tomo el recuento de las celdas y hago un cálculo (muy similar) para restablecer el ancho.

let newWidth = (items.count * cellWidth) + (items.count * cellSpacing)

Luego establezco el .constantvalor de la salida de restricción en el resultado del cálculo y la distribución automática hace el resto.

Esto puede entrar en conflicto con `UICollectionViewDelegateFlowLayout, pero esto funcionó perfectamente para crear una vista de colección justificada a la izquierda. Sin un delegado, solo parece funcionar cuando las celdas llenan la mayoría de la vista.

Brooks DuBois
fuente
0

Solución general para flowlayout que centra las páginas si son menores que el ancho y se alinea a la izquierda si hay más

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    // Centering if there are fever pages
    CGSize itemSize = [(UICollectionViewFlowLayout *)collectionViewLayout itemSize];
    CGFloat spacing = [(UICollectionViewFlowLayout *)collectionViewLayout minimumLineSpacing];

    NSInteger count = [self collectionView:self numberOfItemsInSection:section];
    CGFloat totalCellWidth = itemSize.width * count;
    CGFloat totalSpacingWidth = spacing * ((count - 1) < 0 ? 0 : count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    if (leftInset < 0) {
        UIEdgeInsets inset = [(UICollectionViewFlowLayout *)collectionViewLayout sectionInset];
        return inset;
    }
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}

Versión rápida (convertida de ObjC)

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    // Centering if there are fever pages
    let itemSize: CGSize? = (collectionViewLayout as? UICollectionViewFlowLayout)?.itemSize
    let spacing: CGFloat? = (collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing

    let count: Int = self.collectionView(self, numberOfItemsInSection: section)
    let totalCellWidth = (itemSize?.width ?? 0.0) * CGFloat(count)
    let totalSpacingWidth = (spacing ?? 0.0) * CGFloat(((count - 1) < 0 ? 0 : count - 1))
    let leftInset: CGFloat = (bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2
    if leftInset < 0 {
        let inset: UIEdgeInsets? = (collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset
        return inset!
    }
    let rightInset: CGFloat = leftInset
    let sectionInset = UIEdgeInsets(top: 0, left: Float(leftInset), bottom: 0, right: Float(rightInset))
    return sectionInset
}

Sin título-3.png

Peter Lapisu
fuente
¿Qué son los límites en el código rápido? Estoy obteniendo el uso de un identificador no resuelto 'límites' de error
Sachin Tanpure
Hola, en mi ejemplo, implementé el método dentro de una UIView, que tiene límites, si lo está implementando en otro lugar, use los límites apropiados
Peter Lapisu
0

la forma más simple es establecer el tamaño estimado de la vista de colección en Ninguno en el guión gráfico o con código layout.estimatedItemSize = CGSize.zero

remykits
fuente
0

Si sólo hay espacio para una célula por grupo, una leading:y trailing:del .flexible(0)centrará la celda horizontalmente:

item.edgeSpacing = NSCollectionLayoutEdgeSpacing(
    leading: .flexible(0), top: nil,                                                     
    trailing: .flexible(0), bottom: nil
)
Bruno
fuente
0

Usé ese código en un proyecto. Centra el collectionView horizontal y verticalmente en ambas direcciones .horizontaly .verticalusando las inserciones de sección. Respeta el espaciado y el recuadro original de la sección si está configurado. Código para usar en el delegado UICollectionViewDelegateFlowLayoutpara que tengamos acceso a todas las propiedades que necesitamos recuperar del UIcollectionViewo establecer en el guión gráfico para su reutilización.

// original function of the delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    // casting the layout as a UICollectionViewFlowLayout to have access to the properties of items for reusability - you could also link the real one from the storyboard with an outlet
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    // getting all the properties we need
    let itemWidth = flowLayout.itemSize.width
    let itemHeight = flowLayout.itemSize.height
    let interSpacing = flowLayout.minimumInteritemSpacing
    let lineSpacing = flowLayout.minimumLineSpacing
    // getting the size of the collectionView
    let collectionWidth = collectionView.bounds.width
    let collectionHeight = collectionView.bounds.height
    // getting the direction to choose how to align the collection
    let direction = flowLayout.scrollDirection
    // you don't want to have an item greater than the collection
    guard (itemWidth < collectionWidth && direction == .vertical) || (itemHeight < collectionHeight && direction == .horizontal) else {
        print("Really?")
        return UIEdgeInsets(top: flowLayout.sectionInset.top, left: flowLayout.sectionInset.left, bottom: flowLayout.sectionInset.bottom, right: flowLayout.sectionInset.right)
    }
    // getting the number of item in the current section
    let totalItemCount = CGFloat(collectionView.numberOfItems(inSection: section))
    // setting number of item in a row to the max number of items that can fit in a row without spacing or to the number of items in the section if less than the max
    var itemCountInRow = totalItemCount < (collectionWidth / itemWidth).rounded(.towardZero) ? totalItemCount : (collectionWidth / itemWidth).rounded(.towardZero)
    // how many max row can we have
    var countOfRow = totalItemCount < (collectionHeight / itemHeight).rounded(.towardZero) ? totalItemCount : (collectionHeight / itemHeight).rounded(.towardZero)
    // calculating the total width of row by multiplying the number of items in the row by the width of item and adding the spacing multiplied by the number of item minus one
    var totalWidthOfRow:CGFloat {
        get{
            return (itemWidth * itemCountInRow) + (interSpacing * (itemCountInRow - 1))
        }
    }
    // calculating the total height of row by multiplying the number of row by the height of item and adding the spacing multiplied by the number of row minus one
    var totalHeightOfRow:CGFloat {
        get{
            return (itemHeight * countOfRow) + (lineSpacing * (countOfRow - 1))
        }
    }
    // first we set the inset to the default
    var edgeInsetLeft = flowLayout.sectionInset.left
    var edgeInsetTop = flowLayout.sectionInset.top

    if direction == .vertical {
        // while the width of row with original margin is greater than the width of the collection we drop one item until it fits
        while totalWidthOfRow > collectionWidth || ((collectionWidth - totalWidthOfRow) / 2) < flowLayout.sectionInset.left {
            // droping an item to fit in the row
            itemCountInRow -= 1
        }
        // calculating the number of rows in collectionView by dividing the number of items by the number of items in a row
        countOfRow = (totalItemCount / (itemCountInRow)).rounded(.up)
    } else {
        itemCountInRow = (totalItemCount / countOfRow).rounded(.up)
        // while the height of row with original marginis greater than the height of the collection we drop one row until it fits
        while totalHeightOfRow >= collectionHeight  || ((collectionHeight - totalHeightOfRow) / 2) < flowLayout.sectionInset.top  {
            // droping an item to fit in the row
            countOfRow -= 1
        }
    }
    edgeInsetLeft = max(flowLayout.sectionInset.left, (collectionWidth - totalWidthOfRow) / 2)
    edgeInsetTop = max(flowLayout.sectionInset.top, (collectionHeight - totalHeightOfRow) / 2)
    // we don't specially need insets where the items are overflowing
    let edgeInsetRight = direction == .vertical ? edgeInsetLeft : flowLayout.sectionInset.right
    let edgeInsetBottom = direction == .horizontal ? edgeInsetTop : flowLayout.sectionInset.bottom
    // returning the UIEdgeInsets
    return UIEdgeInsets(top: edgeInsetTop, left: edgeInsetLeft, bottom: edgeInsetBottom, right: edgeInsetRight)
}

Espero que ayude a alguien: centra la sección, no los elementos dentro de la sección, para más tenemos que subclasificar el UICollectionViewFlowLayouto UICollectionViewLayoutcomo el ejemplo de mosaico de Apple.

doroboneko
fuente
-3

Creo que necesita centrar la celda, por lo que en lugar de usar collectionView, me gustaría que UITableView sea de gran utilidad. Simplemente use un UIViewController y coloque dos UIViews al frente y atrás y coloque un UITableViewen el medio Espero que esto ayude

Misha
fuente
Agregué una foto, para mostrarte exactamente lo que necesito, ¡gracias!
RaptoX