Comment centrer horizontalement les cellules UICollectionView?

124

J'ai fait quelques recherches, mais je n'ai trouvé aucun exemple de code sur la façon de centrer des cellules dans un UICollectionView horizontalement.

au lieu que la première cellule soit comme ce X00 , je veux que ce soit comme ça 0X0 . y a-t-il un moyen d'accomplir cela?

ÉDITER:

pour visualiser ce que je veux:

entrez la description de l'image ici

J'en ai besoin pour ressembler à la version B lorsqu'il n'y a qu'un seul élément dans CollectionView. Quand j'ai plus d'un élément, cela devrait être comme la version A mais avec plus d'éléments.

Pour le moment, cela ressemble à la version A alors que je n'ai qu'un seul élément, et je me demande comment je peux le faire ressembler à B.

Merci pour l'aide!

RaptoX
la source
N'est-il pas plus facile de laisser la cellule s'adapter à la largeur de la vue de collection, puis de centrer la vue de collection elle-même dans son parent?
Arthur Gevorkyan du
oui, il y a au moins deux façons de le faire, la première (rapide) est de créer une largeur de cellule sur tout l'écran et de centrer sa vue enfant. deuxième (à droite) implémenter la disposition de vue de collection personnalisée
sage444
Il y aura éventuellement plus de cellules provenant du backend, remplir toute la largeur ne serait pas une bonne idée
RaptoX
augmenter la largeur est suffisant pour mettre au centre
Kishore Kumar
Double
kelin

Réponses:

229

Ce n'est pas une bonne idée d'utiliser une bibliothèque, si votre but n'est que cela, c'est-à-dire aligner au centre.

Mieux vous pouvez faire ce calcul simple dans votre fonction 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.
la source
2
@ DarshanPatel.Merci beaucoup de la réponse, j'ai implémenté cela et les lignes sont venues au centre comme il se doit, mais maintenant le problème est que je ne peux pas faire défiler jusqu'au premier élément. Lorsque j'essaie de faire défiler jusqu'au premier élément, cela me ramène aux UIEdgeInsets modifiés. Vous pouvez voir mon application de démonstration github.com/anirudha-music/CollectionViewCenter
Anirudha Mahale
5
Dans Swift 3, la nouvelle signature de méthode est collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int).
Kamchatka
1
comment pouvez-vous saisir le cellWidth, est-ce possible grâce à la méthode cellForItemAt? J'ai essayé et il est retourné nul .. la largeur de la cellule pour moi change en fonction de la taille de l'écran .. @DarshanPatel.
Chris
10
@DarshanPatel. Votre réponse peut parfois produire une valeur négative sur des appareils plus petits. Pensez à utiliser une vérification maximale de votre leftInsetvaleur comme ceci:let leftInset = max(0.0, (self.collectionView.bounds.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2)
Rhuari Glen
3
Si vous ne sous-classez pas UICollectionViewController, assurez-vous que votre classe est conforme à UICollectionViewDelegateFlowLayout sinon cela ne fonctionnera pas
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'oubliez pas d'ajouter le protocole

UICollectionViewDelegateFlowLayout
Ahmed Safadi
la source
contrainte peut-être @ashForIos
Ahmed Safadi
Votre réponse fonctionne correctement lorsqu'il y a des cellules qui correspondent à collectionView lorsque le nombre de cellules augmente, les cellules sont au centre et vous ne pouvez pas faire défiler les premières cellules ou la dernière.
NickCoder
2
@Vitalii 80 signifie largeur de cellule, et 10 l'espace entre les cellules, si vous lisez le nom de la variable, vous comprendrez ce que cela signifie: P
Ahmed Safadi le
La solution Swift 4.2 est plus simple, MERCI! Assurez-vous simplement de régler le "80" sur la largeur réelle de votre cellule-objet.
John Pitts
25

Essayez ceci pour 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)
    }

Ajoutez votre cellWidth à la place de 165,0

Oscar Castellon
la source
1
C'est la meilleure réponse. Avec les mathématiques les plus simples. fonctionne avec n'importe quel nombre de lignes et de colonnes
rickrvo
20

J'utilise KTCenterFlowLayout pour cela, et cela fonctionne très bien. C'est une sous-classe personnalisée UICollectionViewFlowLayoutqui centre les cellules comme vous le souhaitez. (Remarque: ce n'est pas une chose triviale à résoudre en publiant du code, c'est pourquoi je crée un lien vers un projet GitHub!)

Deux pailles
la source
Impossible de le faire fonctionner à partir d'IB. Cette bibliothèque a fonctionné comme un charme pour moi. Je viens d'installer le pod et de changer la classe de mise en page dans IB!
tagirkaZ le
15

Une version objective-C de la réponse 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
la source
Merci. Son fonctionne bien avec une seule rangée. mais créant un problème sur plusieurs rangées. Im pas en mesure d'ajouter une URL ici pour montrer la capture d'écran u. . mais vous pouvez ajouter "yynoalzg" dans une petite URL. vous aurez une idée. La section or a 4 enregistrements. Le quatrième devrait être dans une nouvelle ligne. .mais après cette méthode, il s'affiche comme ça ... laissez-moi savoir si une idée.
Hitarth
6

En modifiant légèrement la réponse de @Safad Funy, c'est ce qui a fonctionné pour moi dans la dernière version de Swift & iOS. Dans ce cas, je voulais que la largeur des cellules soit un tiers de la taille de la vue de collection.

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
la source
2
Cela a fonctionné pour moi en particulier, lorsqu'il n'y a qu'une seule cellule.
Dasoga
6

Vous pouvez utiliser cette extension (Swift 4).

Il peut centrer les cellules avec si vous en collectionViewavez layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize.

Il fonctionne avec toutes les tailles de cellules et fonctionne parfaitement lorsque 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)
    }
}

J'espère que cela vous aidera!

S. Matsepura
la source
1
Obtention d'erreur: Thread 1: EXC_BAD_ACCESS (code = 2, adresse = 0x118ffde58)
atulkhatri
4

Swift 4.2 (horizontalement et verticalement). C'est une petite mise à jour du code Pink Panther et un grand merci!


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)

    }
}

Assurez-vous que votre classe est conforme au protocole UICollectionViewDelegateFlowLayout

EVGENIY DANILOV
la source
Vraiment votre code fonctionne très bien pour moi, merci mec; )
steveSarsawa
4

Voici la nouvelle version pour Swift 5 qui fonctionne également très bien lorsque les cellules sont plus d'une ligne:

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

Veuillez vous assurer que votre classe est conforme au UICollectionViewDelegateFlowLayoutprotocole.

Saeed Ir
la source
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
la source
2

Pour les personnes qui souhaitent uniquement ajouter un rembourrage ( haut, gauche, bas, droite ):

Ajouter le protocole UICollectionViewDelegateFlowLayout

Cet exemple montre un remplissage à gauche et à droite avec 40.

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

Vous pouvez essayer ma solution, cela fonctionne 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
la source
1

La réponse acceptée est la bonne réponse, mais si votre totalCellWidthest inférieur au CollectionViews width, mais juste pour vous prémunir contre cela, vous pouvez faire comme ci-dessous.

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

Ce code doit centrer horizontalement la vue de la collection même dans Swift 4.0 sans aucune modification:

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

Assurez-vous que votre classe est conforme au UICollectionViewDelegateFlowLayoutprotocole

Saeed Ir
la source
0

J'ai fini par adopter une approche complètement différente ici, ce qui, je crois, mérite d'être mentionné.

J'ai défini une contrainte sur la vue de ma collection pour qu'elle soit alignée horizontalement au centre. Ensuite, j'ai défini une autre contrainte qui spécifie la largeur. J'ai créé une sortie pour la contrainte de largeur à l' intérieur de mon viewController qui contient la vue de collection. Ensuite, lorsque ma source de données est modifiée et que je mets à jour la vue de la collection, je prends le nombre de cellules et fais un calcul (très similaire) pour réinitialiser la largeur.

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

Ensuite, je règle la .constantvaleur de la prise de contrainte sur le résultat du calcul et la mise en page automatique fait le reste.

Cela peut entrer en conflit avec le `UICollectionViewDelegateFlowLayout, mais cela a parfaitement fonctionné pour moi pour créer une vue de collection justifiée à gauche. Sans délégué, cela ne semble fonctionner que lorsque les cellules remplissent la majorité de la vue.

Brooks DuBois
la source
0

Solution générale pour la disposition des flux qui centre les pages si elles sont inférieures à la largeur et s'aligne à gauche s'il y en a plus

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

Version Swift (convertie depuis 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
}

Sans titre-3.png

Peter Lapisu
la source
Que sont les limites du code SWIFT? J'obtiens une erreur d'utilisation non résolue des limites de l'identificateur
Sachin Tanpure
Bonjour, dans mon exemple, j'ai implémenté la méthode dans un UIView, qui a des limites, si vous l'implémentez ailleurs, utilisez les limites appropriées
Peter Lapisu
0

J'ai une situation similaire dans le projet, et je l'ai corrigée en me référant UPCarouselFlowLayout

Je pense qu'il prend en charge la swift 5version

https://github.com/ink-spot/UPCarouselFlowLayout/blob/master/UPCarouselFlowLayout/UPCarouselFlowLayout.swift

Regardez l'implémentation du code dans

override open func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint
Raj
la source
0

le moyen le plus simple consiste à définir la taille estimée de la vue de collection sur Aucune dans le storyboard ou avec le code layout.estimatedItemSize = CGSize.zero

remykits
la source
0

S'il n'y a de place que pour une cellule par groupe, un leading:et trailing:de .flexible(0)centreront la cellule horizontalement:

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

J'ai utilisé ce code dans un projet. Il centre la collectionView horizontalement et verticalement dans les deux sens .horizontalet en .verticalutilisant les inserts de section. Respecte l'espacement et l'encart d'origine de la section s'il est défini. Code à utiliser dans le délégué UICollectionViewDelegateFlowLayoutafin que nous ayons accès à toutes les propriétés que nous devons récupérer à partir de UIcollectionViewou définies dans le storyboard pour la réutilisation.

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

J'espère que cela aiderait quelqu'un - il centre la section pas les éléments à l'intérieur de la section, pour plus, nous devons sous-classer le UICollectionViewFlowLayoutou UICollectionViewLayoutcomme exemple de mosaïque d'Apple.

Doroboneko
la source
-4

Je pense que vous devez centrer la cellule, donc au lieu d'utiliser collectionView, je voudrais que UITableView soit d'une grande utilité. Utilisez simplement un UIViewController et placez deux UIViews à l'avant et à l'arrière et placez un UITableViewau milieu Espérons que cela aide

Misha
la source
J'ai ajouté une photo, pour vous montrer exactement ce dont j'ai besoin, merci!
RaptoX