web-dev-qa-db-fra.com

Comment centrer les cellules d'un UICollectionView?

J'utilise actuellement UICollectionView pour la grille de l'interface utilisateur, et cela fonctionne bien. Cependant, j'aimerais activer le défilement horizontal. La grille prend en charge 8 éléments par page. Lorsque le nombre total d’éléments est égal à 4, c’est ainsi que les éléments doivent être organisés avec la direction de défilement horizontale activée:

0 0 x x
0 0 x x

Ici 0 -> Objet de collection et x -> Cellules vides

Existe-t-il un moyen de les aligner comme suit:

x 0 0 x
x 0 0 x

Alors que le contenu a l'air plus propre?

L'arrangement ci-dessous pourrait également être une solution à laquelle je m'attends.

0 0 0 0
x x x x
94
RVN

Je pense que vous pouvez obtenir le look d'une seule ligne en implémentant quelque chose comme ceci:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 100, 0, 0);
}

Vous devrez jouer avec ce nombre pour savoir comment forcer le contenu sur une seule ligne. Le premier 0 est l'argument Edge supérieur, vous pouvez également l'ajuster si vous souhaitez centrer le contenu verticalement à l'écran.

79
rdelmar

Pour ceux qui recherchent une solution pour les cellules de collectionview alignées au centre à largeur dynamique , comme je l'étais, j'ai fini par modifier la réponse d'Angel pour ne version alignée à gauche pour créer une sous-classe alignée au centre pour UICollectionViewFlowLayout.

CenterAlignedCollectionViewFlowLayout

// NOTE: Doesn't work for horizontal layout!
class CenterAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let superAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
        // Copy each item to prevent "UICollectionViewFlowLayout has cached frame mismatch" warning
        guard let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] else { return nil }

        // Constants
        let leftPadding: CGFloat = 8
        let interItemSpacing = minimumInteritemSpacing

        // Tracking values
        var leftMargin: CGFloat = leftPadding // Modified to determine Origin.x for each item
        var maxY: CGFloat = -1.0 // Modified to determine Origin.y for each item
        var rowSizes: [[CGFloat]] = [] // Tracks the starting and ending x-values for the first and last item in the row
        var currentRow: Int = 0 // Tracks the current row
        attributes.forEach { layoutAttribute in

            // Each layoutAttribute represents its own item
            if layoutAttribute.frame.Origin.y >= maxY {

                // This layoutAttribute represents the left-most item in the row
                leftMargin = leftPadding

                // Register its Origin.x in rowSizes for use later
                if rowSizes.count == 0 {
                    // Add to first row
                    rowSizes = [[leftMargin, 0]]
                } else {
                    // Append a new row
                    rowSizes.append([leftMargin, 0])
                    currentRow += 1
                }
            }

            layoutAttribute.frame.Origin.x = leftMargin

            leftMargin += layoutAttribute.frame.width + interItemSpacing
            maxY = max(layoutAttribute.frame.maxY, maxY)

            // Add right-most x value for last item in the row
            rowSizes[currentRow][1] = leftMargin - interItemSpacing
        }

        // At this point, all cells are left aligned
        // Reset tracking values and add extra left padding to center align entire row
        leftMargin = leftPadding
        maxY = -1.0
        currentRow = 0
        attributes.forEach { layoutAttribute in

            // Each layoutAttribute is its own item
            if layoutAttribute.frame.Origin.y >= maxY {

                // This layoutAttribute represents the left-most item in the row
                leftMargin = leftPadding

                // Need to bump it up by an appended margin
                let rowWidth = rowSizes[currentRow][1] - rowSizes[currentRow][0] // last.x - first.x
                let appendedMargin = (collectionView!.frame.width - leftPadding  - rowWidth - leftPadding) / 2
                leftMargin += appendedMargin

                currentRow += 1
            }

            layoutAttribute.frame.Origin.x = leftMargin

            leftMargin += layoutAttribute.frame.width + interItemSpacing
            maxY = max(layoutAttribute.frame.maxY, maxY)
        }

        return attributes
    }
}

CenterAlignedCollectionViewFlowLayout

73
Alex Koshy

Les solutions principales ici ne fonctionnaient pas pour moi immédiatement, alors j'ai proposé cette solution qui devrait fonctionner pour toute vue de collection avec défilement horizontal avec présentation du flux et une seule section:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
    {
    // Add inset to the collection view if there are not enough cells to fill the width.
    CGFloat cellSpacing = ((UICollectionViewFlowLayout *) collectionViewLayout).minimumLineSpacing;
    CGFloat cellWidth = ((UICollectionViewFlowLayout *) collectionViewLayout).itemSize.width;
    NSInteger cellCount = [collectionView numberOfItemsInSection:section];
    CGFloat inset = (collectionView.bounds.size.width - (cellCount * cellWidth) - ((cellCount - 1)*cellSpacing)) * 0.5;
    inset = MAX(inset, 0.0);
    return UIEdgeInsetsMake(0.0, inset, 0.0, 0.0);
    }
55
Siegfoult

Il est facile de calculer dynamiquement les incrustations, ce code centre toujours vos cellules:

NSInteger const SMEPGiPadViewControllerCellWidth = 332;

...

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{

    NSInteger numberOfCells = self.view.frame.size.width / SMEPGiPadViewControllerCellWidth;
    NSInteger edgeInsets = (self.view.frame.size.width - (numberOfCells * SMEPGiPadViewControllerCellWidth)) / (numberOfCells + 1);

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

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.collectionView.collectionViewLayout invalidateLayout];
}
34
mientus

Semblable à d'autres réponses, il s'agit d'une réponse dynamique qui devrait fonctionner pour les cellules de taille statique. La seule modification que j'ai faite est que je mets le rembourrage des deux côtés. Si je ne le faisais pas, j'avais des problèmes.


Objectif c

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {

    NSInteger numberOfItems = [collectionView numberOfItemsInSection:section];
    CGFloat combinedItemWidth = (numberOfItems * collectionViewLayout.itemSize.width) + ((numberOfItems - 1) * collectionViewLayout.minimumInteritemSpacing);
    CGFloat padding = (collectionView.frame.size.width - combinedItemWidth) / 2;

    return UIEdgeInsetsMake(0, padding, 0, padding);
}

Swift

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let numberOfItems = CGFloat(collectionView.numberOfItems(inSection: section))
    let combinedItemWidth = (numberOfItems * flowLayout.itemSize.width) + ((numberOfItems - 1)  * flowLayout.minimumInteritemSpacing)
    let padding = (collectionView.frame.width - combinedItemWidth) / 2
    return UIEdgeInsets(top: 0, left: padding, bottom: 0, right: padding)
}

En outre, si vous rencontrez toujours des problèmes, assurez-vous de définir les mêmes valeurs pour minimumInteritemSpacing et minimumLineSpacing, ces dernières semblant liées entre elles.

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
flowLayout.minimumInteritemSpacing = 20.0;
flowLayout.minimumLineSpacing = 20.0;
20
kgaidis

Mettez ceci dans votre délégué de vue de collection. Il prend plus en compte les paramètres de base de la disposition des flux que les autres réponses et est donc plus générique.

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    NSInteger cellCount = [collectionView.dataSource collectionView:collectionView numberOfItemsInSection:section];
    if( cellCount >0 )
    {
        CGFloat cellWidth = ((UICollectionViewFlowLayout*)collectionViewLayout).itemSize.width+((UICollectionViewFlowLayout*)collectionViewLayout).minimumInteritemSpacing;
        CGFloat totalCellWidth = cellWidth*cellCount + spacing*(cellCount-1);
        CGFloat contentWidth = collectionView.frame.size.width-collectionView.contentInset.left-collectionView.contentInset.right;
        if( totalCellWidth<contentWidth )
        {
            CGFloat padding = (contentWidth - totalCellWidth) / 2.0;
            return UIEdgeInsetsMake(0, padding, 0, padding);
        }
    }
    return UIEdgeInsetsZero;
}

Version rapide (merci g0ld2k):

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

    // Translated from Objective-C version at: http://stackoverflow.com/a/27656363/309736

        let cellCount = CGFloat(viewModel.getNumOfItemsInSection(0))

        if cellCount > 0 {
            let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
            let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing
            let totalCellWidth = cellWidth*cellCount + spacing*(cellCount-1)
            let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right

            if (totalCellWidth < contentWidth) {
                let padding = (contentWidth - totalCellWidth) / 2.0
                return UIEdgeInsetsMake(0, padding, 0, padding)
            }
        }

        return UIEdgeInsetsZero
    }
}
19
bert

Ma solution pour les cellules de vue de collection de taille statique qui nécessitent un remplissage à gauche et à droite.

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

    let flowLayout = (collectionViewLayout as! UICollectionViewFlowLayout)
    let cellSpacing = flowLayout.minimumInteritemSpacing
    let cellWidth = flowLayout.itemSize.width
    let cellCount = CGFloat(collectionView.numberOfItemsInSection(section))

    let collectionViewWidth = collectionView.bounds.size.width

    let totalCellWidth = cellCount * cellWidth
    let totalCellSpacing = cellSpacing * (cellCount - 1)

    let totalCellsWidth = totalCellWidth + totalCellSpacing

    let edgeInsets = (collectionViewWidth - totalCellsWidth) / 2.0

    return edgeInsets > 0 ? UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets) : UIEdgeInsetsMake(0, cellSpacing, 0, cellSpacing)
}
11
Sagar Natekar

Swift 2.0 fonctionne bien pour moi!

 func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
        let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
        return UIEdgeInsetsMake(0, edgeInsets, 0, 0);
    }

Où: screenWight: c'est essentiellement la largeur de ma collection (largeur d'écran) - J'ai créé des constantes: laissez screenWight: CGFloat = UIScreen.mainScreen (). Bounds.width car self.view.bounds s'affiche à chaque fois. 600 - coz de SizeClasses elements - tableau de cellules 5 - ma largeur de cellule manuelle 1 - ma distance entre les cellules

8
Dmitrii Z

J'ai une barre de balises dans mon application qui utilise un UICollectionView & UICollectionViewFlowLayout, avec une rangée de cellules alignée au centre.

Pour obtenir le retrait correct, vous soustrayez la largeur totale de toutes les cellules (espacement compris) de la largeur de votre UICollectionView, et vous divisez par deux.

[........Collection View.........]
[..Cell..][..Cell..]
                   [____indent___] / 2

=

[_____][..Cell..][..Cell..][_____]

Le problème est cette fonction -

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;

s'appelle avant ...

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;

... afin que vous ne puissiez pas parcourir vos cellules pour déterminer la largeur totale.

Au lieu de cela, vous devez calculer à nouveau la largeur de chaque cellule. Dans mon cas, j’utilise [NSString sizeWithFont: ... ], Car la largeur de ma cellule est déterminée par le UILabel lui-même.

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    CGFloat rightEdge = 0;
    CGFloat interItemSpacing = [(UICollectionViewFlowLayout*)collectionViewLayout minimumInteritemSpacing];

    for(NSString * tag in _tags)
        rightEdge += [tag sizeWithFont:[UIFont systemFontOfSize:14]].width+interItemSpacing;

    // To center the inter spacing too
    rightEdge -= interSpacing/2;

    // Calculate the inset
    CGFloat inset = collectionView.frame.size.width-rightEdge;

    // Only center align if the inset is greater than 0
    // That means that the total width of the cells is less than the width of the collection view and need to be aligned to the center.
    // Otherwise let them align left with no indent.

    if(inset > 0)
        return UIEdgeInsetsMake(0, inset/2, 0, 0);
    else
        return UIEdgeInsetsMake(0, 0, 0, 0);
}
8
Siôn

Dans Swift, ce qui suit distribuera les cellules de manière uniforme en appliquant la quantité de rembourrage correcte sur les côtés de chaque cellule. Bien sûr, vous devez d'abord connaître/définir la largeur de votre cellule.

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

        var cellWidth : CGFloat = 110;

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

        return UIEdgeInsetsMake(0, edgeInsets, 60.0, edgeInsets);
}
8
Dale Clifford

Vous pouvez utiliser https://github.com/keighl/KTCenterFlowLayout comme ceci:

KTCenterFlowLayout *layout = [[KTCenterFlowLayout alloc] init];

[self.collectionView setCollectionViewLayout:layout];
6
user3419059

Vous ne savez pas si cela est nouveau dans Xcode 5 ou non, mais vous pouvez maintenant ouvrir l'inspecteur de taille via Interface Builder et y définir un encadré. Cela vous évitera d'avoir à écrire du code personnalisé pour le faire pour vous et devrait augmenter considérablement la vitesse à laquelle vous trouvez les décalages appropriés.

2
Sandy Chapman

Une autre façon de faire est de régler le collectionView.center.x, ainsi:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if let
        collectionView = collectionView,
        layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    {
        collectionView.center.x = view.center.x + layout.sectionInset.right / 2.0
    }
}

Dans ce cas, ne respectez que le bon encadré qui me convient.

1
Paul Peelen

Sur la base de la réponse de user3676011, je peux suggérer une réponse plus détaillée avec une petite correction. Cette solution fonctionne très bien sur Swift 2..

enum CollectionViewContentPosition {
    case Left
    case Center
}

var collectionViewContentPosition: CollectionViewContentPosition = .Left

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

    if collectionViewContentPosition == .Left {
        return UIEdgeInsetsZero
    }

    // Center collectionView content

    let itemsCount: CGFloat = CGFloat(collectionView.numberOfItemsInSection(section))
    let collectionViewWidth: CGFloat = collectionView.bounds.width

    let itemWidth: CGFloat = 40.0
    let itemsMargin: CGFloat = 10.0

    let edgeInsets = (collectionViewWidth - (itemsCount * itemWidth) - ((itemsCount-1) * itemsMargin)) / 2

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

Il y avait un problème dans

(CGFloat (elements.count) * 10))

où devrait être supplémentaire -1 mentionné.

1
Novamax

Version de travail de la réponse Objective C de kgaidis utilisant Swift 3.0:

let flow = UICollectionViewFlowLayout()

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {        
    let numberOfItems = collectionView.numberOfItems(inSection: 0)
    let combinedItemWidth:CGFloat = (CGFloat(numberOfItems) * flow.itemSize.width) + ((CGFloat(numberOfItems) - 1) * flow.minimumInteritemSpacing)
    let padding = (collectionView.frame.size.width - combinedItemWidth) / 2

    return UIEdgeInsetsMake(0, padding, 0, padding)
}
1
RJH

Voici comment j'ai obtenu une vue de collection centrée sur un espacement interitem fixe

#define maxInteritemSpacing 6
#define minLineSpacing 3

@interface MyFlowLayout()<UICollectionViewDelegateFlowLayout>

@end

@implementation MyFlowLayout

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.minimumInteritemSpacing = 3;
        self.minimumLineSpacing = minLineSpacing;
        self.scrollDirection = UICollectionViewScrollDirectionVertical;
    }
    return self;
}

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *answer = [super layoutAttributesForElementsInRect:rect];

    if (answer.count > 0) {
        NSMutableArray<NSMutableArray<UICollectionViewLayoutAttributes *> *> *rows = [NSMutableArray array];
        CGFloat maxY = -1.0f;
        NSInteger currentRow = 0;

        //add first item to row and set its maxY
        [rows addObject:[@[answer[0]] mutableCopy]];
        maxY = CGRectGetMaxY(((UICollectionViewLayoutAttributes *)answer[0]).frame);

        for(int i = 1; i < [answer count]; ++i) {
            //handle maximum spacing
            UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
            UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
            NSInteger maximumSpacing = maxInteritemSpacing;
            NSInteger Origin = CGRectGetMaxX(prevLayoutAttributes.frame);

            if(Origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
                CGRect frame = currentLayoutAttributes.frame;
                frame.Origin.x = Origin + maximumSpacing;
                currentLayoutAttributes.frame = frame;
            }

            //handle center align
            CGFloat currentY = currentLayoutAttributes.frame.Origin.y;
            if (currentY >= maxY) {
                [self shiftRowToCenterForCurrentRow:rows[currentRow]];

                //next row
                [rows addObject:[@[currentLayoutAttributes] mutableCopy]];
                currentRow++;
            }
            else {
                //same row
                [rows[currentRow] addObject:currentLayoutAttributes];
            }

            maxY = MAX(CGRectGetMaxY(currentLayoutAttributes.frame), maxY);
        }

        //mark sure to shift 1 row items
        if (currentRow == 0) {
            [self shiftRowToCenterForCurrentRow:rows[currentRow]];
        }
    }

    return answer;
}

- (void)shiftRowToCenterForCurrentRow:(NSMutableArray<UICollectionViewLayoutAttributes *> *)currentRow
{
    //shift row to center
    CGFloat endingX = CGRectGetMaxX(currentRow.lastObject.frame);
    CGFloat shiftX = (self.collectionViewContentSize.width - endingX) / 2.f;
    for (UICollectionViewLayoutAttributes *attr in currentRow) {
        CGRect shiftedFrame = attr.frame;
        shiftedFrame.Origin.x += shiftX;
        attr.frame = shiftedFrame;
    }
}

@end
1
Zhong Huiwen

Voici ma solution avec quelques hypothèses:

  • il n'y a qu'une section
  • les encarts gauche et droit sont égaux
  • la hauteur de la cellule est la même

N'hésitez pas à vous adapter à vos besoins.

Disposition centrée avec largeur de cellule variable:

protocol HACenteredLayoutDelegate: UICollectionViewDataSource {
    func getCollectionView() -> UICollectionView
    func sizeOfCell(at index: IndexPath) -> CGSize
    func contentInsets() -> UIEdgeInsets
}

class HACenteredLayout: UICollectionViewFlowLayout {
    weak var delegate: HACenteredLayoutDelegate?
    private var cache = [UICollectionViewLayoutAttributes]()
    private var contentSize = CGSize.zero
    override var collectionViewContentSize: CGSize { return self.contentSize }

    required init(delegate: HACenteredLayoutDelegate) {
        self.delegate = delegate
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func invalidateLayout() {
        cache.removeAll()
        super.invalidateLayout()
    }

    override func prepare() {
        if cache.isEmpty && self.delegate != nil && self.delegate!.collectionView(self.delegate!.getCollectionView(), numberOfItemsInSection: 0) > 0 {
            let insets = self.delegate?.contentInsets() ?? UIEdgeInsets.zero
            var rows: [(width: CGFloat, count: Int)] = [(0, 0)]
            let viewWidth: CGFloat = UIScreen.main.bounds.width
            var y = insets.top
            var unmodifiedIndexes = [IndexPath]()
            for itemNumber in 0 ..< self.delegate!.collectionView(self.delegate!.getCollectionView(), numberOfItemsInSection: 0) {
                let indexPath = IndexPath(item: itemNumber, section: 0)
                let cellSize = self.delegate!.sizeOfCell(at: indexPath)
                let potentialRowWidth = rows.last!.width + (rows.last!.count > 0 ? self.minimumInteritemSpacing : 0) + cellSize.width + insets.right + insets.left
                if potentialRowWidth > viewWidth {
                    let leftOverSpace = max((viewWidth - rows[rows.count - 1].width)/2, insets.left)
                    for i in unmodifiedIndexes {
                        self.cache[i.item].frame.Origin.x += leftOverSpace
                    }
                    unmodifiedIndexes = []
                    rows.append((0, 0))
                    y += cellSize.height + self.minimumLineSpacing
                }
                unmodifiedIndexes.append(indexPath)
                let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
                rows[rows.count - 1].count += 1
                rows[rows.count - 1].width += rows[rows.count - 1].count > 1 ? self.minimumInteritemSpacing : 0
                attribute.frame = CGRect(x: rows[rows.count - 1].width, y: y, width: cellSize.width, height: cellSize.height)
                rows[rows.count - 1].width += cellSize.width
                cache.append(attribute)
            }
            let leftOverSpace = max((viewWidth - rows[rows.count - 1].width)/2, insets.left)
            for i in unmodifiedIndexes {
                self.cache[i.item].frame.Origin.x += leftOverSpace
            }
            self.contentSize = CGSize(width: viewWidth, height: y + self.delegate!.sizeOfCell(at: IndexPath(item: 0, section: 0)).height + insets.bottom)
        }
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        var layoutAttributes = [UICollectionViewLayoutAttributes]()

        for attributes in cache {
            if attributes.frame.intersects(rect) {
                layoutAttributes.append(attributes)
            }
        }
        return layoutAttributes
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        if indexPath.item < self.cache.count {
            return self.cache[indexPath.item]
        }
        return nil
    }
}

Résultat:

enter image description here

0
Whitney Foster

Voici comment vous pouvez le faire et 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)
}
0
Anirudha Mahale