Como centralizar horizontalmente as células UICollectionView?

123

Eu fiz algumas pesquisas, mas não consegui encontrar nenhum exemplo de código sobre como centralizar células em um UICollectionView horizontalmente.

em vez de a primeira célula ser como esta X00 , quero que seja assim 0X0 . Existe alguma maneira de conseguir isso?

EDITAR:

para visualizar o que eu quero:

insira a descrição da imagem aqui

Eu preciso que ele se pareça com a versão B quando houver apenas um elemento no CollectionView. Quando obtive mais de um elemento, deveria ser como a versão A, mas com mais elementos.

No momento, parece a Versão A, quando tenho apenas 1 elemento, e me pergunto como posso fazê-la parecer B.

Obrigado pela ajuda!

RaptoX
fonte
Não é mais fácil permitir que a célula se ajuste à largura da exibição de coleção e centralizar a exibição de coleção em seu pai?
Arthur Gevorkyan
sim, há pelo menos duas maneiras de fazer isso, primeiro (rápido) é tornar a largura da célula da tela inteira e centralizar sua exibição filho. segundo (direita) implementar costume coleção de exibição de layout
sage444
Haverá, eventualmente, mais células provenientes do backend, preenchendo toda a largura não seria uma boa ideia
RAPTOX
aumentar a largura é suficiente para pôr em centro
Kishore Kumar

Respostas:

227

Não é uma boa ideia usar uma biblioteca, se o seu objetivo for apenas isso, ou seja, centralizar o alinhamento.

Melhor você pode fazer esse cálculo simples em sua função 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.
fonte
2
@ DarshanPatel.Thanks muita resposta que eu implementei isso e as linhas ficaram no centro como deveria, mas agora o problema é que não posso rolar para o primeiro item. Quando tento rolar para o primeiro item, ele retorna aos UIEdgeInsets modificados. Você pode ver meu aplicativo de demonstração github.com/anirudha-music/CollectionViewCenter
Anirudha Mahale 15/17
5
No Swift 3, a nova assinatura do método é collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int).
28617 Kamchatka
1
como você é capaz de capturar o cellWidth, é possível através do método cellForItemAt? eu tentei e ele retornou nulo .. a largura da célula para mim muda com base no tamanho da tela .. @DarshanPatel.
Chris
10
@DarshanPatel. Às vezes, sua resposta pode produzir um valor negativo em dispositivos menores. Considere o uso de um cheque no máximo em você leftInsetvaloriza assim:let leftInset = max(0.0, (self.collectionView.bounds.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2)
Rhuari Glen
3
Se você não está subclasse UICollectionViewController, verifique se o conforma classe para UICollectionViewDelegateFlowLayout caso contrário não vai 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)

    }

não esqueça de adicionar o protocolo

UICollectionViewDelegateFlowLayout
Ahmed Safadi
fonte
restrição talvez @ashForIos
Ahmed Safadi
Sua resposta funciona bem quando há células que se encaixam no collectionView quando a contagem de células aumenta as células estão no centro e você não pode rolar para a primeira ou a última célula.
NickCoder
2
@Vitalii 80 significa largura da célula e 10 o espaço entre as células, se você ler o nome da variável, entenderia o que significa: P
Ahmed Safadi
A solução Swift 4.2 é mais fácil, OBRIGADO! Apenas certifique-se de definir o "80" para a largura real do objeto da célula.
John Pitts
25

Tente isso para o 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)
    }

Adicione sua cellWidth em vez de 165.0

oscar castellon
fonte
1
Esta é a melhor resposta. Com a matemática mais simples. funciona com qualquer número de linhas e colunas
rickrvo
20

Eu uso o KTCenterFlowLayout para isso e funciona muito bem. É uma subclasse personalizada UICollectionViewFlowLayoutque centraliza as células como você deseja. (Nota: isso não é algo trivial a ser resolvido postando algum código, e é por isso que estou vinculando a um projeto do GitHub!)

TwoStraws
fonte
Não foi possível fazê-lo funcionar do IB. Essa biblioteca funcionou como um encanto para mim. Acabei de instalar o pod e alterei a classe do layout no IB!
tagirkaZ 26/06
15

Uma versão C do objetivo da resposta 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;
}
Stunner
fonte
obrigado. Está funcionando bem com linha única. mas criando problema em várias linhas. não consigo adicionar URL aqui para mostrar sua captura de tela. . mas você pode adicionar "yynoalzg" em um URL minúsculo. você vai ter uma ideia. Seção de ouro tem 4 registro. 4 deve estar em nova linha. .mas após esse método, ele é exibido assim ... deixe-me saber se tem alguma idéia.
Hitarth 26/04/19
6

Modificando ligeiramente a resposta do @Safad Funy, foi isso que funcionou para mim na versão mais recente do Swift e iOS. Nesse caso, eu queria que a largura das células fosse um terço do tamanho da visualização da coleção.

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
fonte
2
Isso funcionou especialmente para mim, quando há apenas uma célula.
Dasoga 9/09/19
6

Você pode usar esta extensão (Swift 4).

Pode centralizar as células se você collectionViewtiver layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize.

Funciona com qualquer tamanho de célula e funciona perfeitamente quando 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 seja de ajuda!

S. Matsepura
fonte
1
Obtendo erro: Tópico 1: EXC_BAD_ACCESS (código = 2, endereço = 0x118ffde58)
atulkhatri 10/10
4

Swift 4.2 (horizontal e vertical). É uma pequena atualização do código da Pantera Cor-de-Rosa e muito obrigado!


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)

    }
}

Verifique se sua classe está em conformidade com o protocolo UICollectionViewDelegateFlowLayout

EVGENIY DANILOV
fonte
Realmente seu código funciona muito bem para mim, obrigado Cara; )
steveSarsawa
4

Aqui está a versão mais recente do Swift 5, que também funciona bem quando as células têm mais de uma linha:

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
    }
}

Certifique-se de que sua classe esteja em conformidade com o UICollectionViewDelegateFlowLayoutprotocolo.

Saeed Ir
fonte
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
fonte
2

Para as pessoas que desejam adicionar apenas um preenchimento ( superior, esquerdo, inferior, direito ):

Adicione o protocolo UICollectionViewDelegateFlowLayout

Este exemplo mostra um preenchimento esquerdo e direito com 40.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {        
    return UIEdgeInsetsMake(0, 40, 0, 40)
}
cadeirinha
fonte
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
fonte
1

Você pode tentar minha solução, funciona bem,

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
fonte
1

A resposta aceita é a resposta certa, mas se o seu totalCellWidthé menor do que os CollectionView's width, mas apenas para se proteger contra isso, você pode fazer como abaixo.

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

Esse código deve centralizar a exibição de coleção horizontalmente, mesmo no Swift 4.0 sem nenhuma modificação:

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
    }
}

Verifique se sua classe está em conformidade com o UICollectionViewDelegateFlowLayoutprotocolo

Saeed Ir
fonte
0

Acabei adotando uma abordagem completamente diferente aqui, que acredito que vale a pena mencionar.

Defino uma restrição na exibição da minha coleção para ser alinhada horizontalmente no centro. Em seguida, defino outra restrição que especifica a largura. Eu criei uma saída para a restrição de largura dentro do meu viewController que mantém a exibição de coleção. Em seguida, quando minha fonte de dados é alterada e estou atualizando a exibição da coleção, tomo a contagem das células e faço um cálculo (muito semelhante) para redefinir a largura.

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

Em seguida, defino o .constantvalor da saída da restrição como resultado do cálculo e o layout automático faz o resto.

Isso pode entrar em conflito com o `UICollectionViewDelegateFlowLayout, mas funcionou perfeitamente para criar uma exibição de coleção justificada à esquerda. Sem um delegado, ele parece funcionar apenas quando as células preenchem a maioria da exibição.

Brooks DuBois
fonte
0

Solução geral para o layout de fluxo que centraliza as páginas se elas forem menores que a largura e alinhar à esquerda se houver mais

- (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;
}

Versão Swift (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
}

Untitled-3.png

Peter Lapisu
fonte
O que são limites no código rápido? erro que eu estou recebendo Uso de identificador não resolvido 'limites'
Sachin Tanpure
Oi, no meu exemplo i implementado o método dentro de um UIView, que tem limites, se você estiver implementando-lo em outro lugar, utilizam os limites apropriados
Peter Lapisu
0

a maneira mais simples é definir o tamanho da estimativa da exibição de coleção como Nenhum no storyboard ou com código layout.estimatedItemSize = CGSize.zero

remykits
fonte
0

Se só há espaço para uma célula por grupo, de um leading:e trailing:de .flexible(0)vai centrar a célula horizontalmente:

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

Eu usei esse código em um projeto. Centraliza o collectionView horizontalmente e verticalmente em ambas as direções .horizontale .verticalusando as inserções da seção. Respeita o espaçamento e a inserção original da seção, se configurada. Código a ser usado no delegado UICollectionViewDelegateFlowLayoutpara termos acesso a todas as propriedades que precisamos recuperar do UIcollectionViewou definido no storyboard para reutilização.

// 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 ajude alguém - ele centraliza a seção e não os itens dentro da seção; para mais, temos que subclassificar o UICollectionViewFlowLayoutou UICollectionViewLayoutcomo exemplo de mosaico da Apple.

doroboneko
fonte
-3

Eu acho que você precisa centralizar a célula, então, em vez de usar o collectionView, como o UITableView, será de grande utilidade. Basta usar um UIViewController e colocar duas UIViews na frente e atrás e colocar uma UITableViewno meio. Espero que isso ajude

Misha
fonte
Adicionei uma foto para mostrar exatamente o que preciso, obrigado!
RaptoX