How to center align the cells of a UICollectionView?

前端 未结 18 2497
梦如初夏
梦如初夏 2020-11-28 01:33

I am currently using UICollectionView for the user interface grid, and it works fine. However, I\'d like to be enable horizontal scrolling. The grid supports 8

18条回答
  •  旧时难觅i
    2020-11-28 01:52

    For those looking for a solution to center-aligned, dynamic-width collectionview cells, as I was, I ended up modifying Angel's answer for a left-aligned version to create a center-aligned subclass for 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
        }
    }
    

提交回复
热议问题