Cell spacing in UICollectionView

后端 未结 26 3239
旧巷少年郎
旧巷少年郎 2020-11-22 15:53

How do I set cell spacing in a section of UICollectionView? I know there is a property minimumInteritemSpacing I have set it to 5.0 still the spaci

相关标签:
26条回答
  • 2020-11-22 16:32

    I have found very easy way to configure spacing between cells or rows by using IB.

    Just select UICollectionView from storyboard/Xib file and click in Size Inspector as specified in below image.

    For configuring space programatically use following properties.

    1) For setting space between rows.

    [self.collectionView setMinimumLineSpacing:5];
    

    2) For setting space between items/cells.

    [self.collectionView setMinimumInteritemSpacing:5];
    
    0 讨论(0)
  • 2020-11-22 16:32

    The voted answer (and also the swift version) has a small issue: there will be a big spacing on the right.

    This is because the flow layout is customised to make the cell spacing exact, with a float left behaviour.

    My solution is to manipulate the section inset, so that the section is align center, yet the spacing is exactly as specified.

    In screenshot below, the item/line spacing is exactly 8pt, while the section left & right inset will be bigger than 8pt (to make it center aligned):

    Swift code as such:

    private let minItemSpacing: CGFloat = 8
    private let itemWidth: CGFloat      = 100
    private let headerHeight: CGFloat   = 32
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        // Create our custom flow layout that evenly space out the items, and have them in the center
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
        layout.minimumInteritemSpacing = minItemSpacing
        layout.minimumLineSpacing = minItemSpacing
        layout.headerReferenceSize = CGSize(width: 0, height: headerHeight)
    
        // Find n, where n is the number of item that can fit into the collection view
        var n: CGFloat = 1
        let containerWidth = collectionView.bounds.width
        while true {
            let nextN = n + 1
            let totalWidth = (nextN*itemWidth) + (nextN-1)*minItemSpacing
            if totalWidth > containerWidth {
                break
            } else {
                n = nextN
            }
        }
    
        // Calculate the section inset for left and right. 
        // Setting this section inset will manipulate the items such that they will all be aligned horizontally center.
        let inset = max(minItemSpacing, floor( (containerWidth - (n*itemWidth) - (n-1)*minItemSpacing) / 2 ) )
        layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)
    
        collectionView.collectionViewLayout = layout
    }
    
    0 讨论(0)
  • 2020-11-22 16:32

    Storyboard Approach

    Select CollectionView in your storyboard and go to size inspector and set min spacing for cells and lines as 5

    Swift 5 Programmatically

    lazy var collectionView: UICollectionView = {
            let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .horizontal
    
            //Provide Width and Height According to your need
            let width = UIScreen.main.bounds.width / 4
            let height = UIScreen.main.bounds.height / 10
            layout.itemSize = CGSize(width: width, height: height)
    
            //For Adjusting the cells spacing
            layout.minimumInteritemSpacing = 5
            layout.minimumLineSpacing = 5
    
            return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        }()
    
    0 讨论(0)
  • 2020-11-22 16:33

    The above solution by vojtech-vrbka is correct but it triggers a warning:

    warning:UICollectionViewFlowLayout has cached frame mismatch for index path - cached value: This is likely occurring because the flow layout subclass Layout is modify attributes returned by UICollectionViewFlowLayout without copying them

    The following code should fix it:

    class CustomViewFlowLayout : UICollectionViewFlowLayout {
    
       let cellSpacing:CGFloat = 4
    
       override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
           let original = super.layoutAttributesForElementsInRect(rect)
    
           if let original = original {
               let attributes = NSArray.init(array: original, copyItems: true) as! [UICollectionViewLayoutAttributes]
    
               for (index, attribute) in attributes.enumerate() {
                    if index == 0 { continue }
                    let prevLayoutAttributes = attributes[index - 1]
                    let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                    if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                        attribute.frame.origin.x = origin + cellSpacing
                    }
                }
                return attributes
           }
           return nil
       }
    }
    
    0 讨论(0)
  • 2020-11-22 16:34

    I stumbled upon a similar problem as OP. Unfortunately the accepted answer did not work for me since the content of the collectionView would not be centered properly. Therefore I came up with a different solution which only requires that all items in the collectionView are of the same width, which seems to be the case in the question:

    #define cellSize 90
    
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
        float width = collectionView.frame.size.width;
        float spacing = [self collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
        int numberOfCells = (width + spacing) / (cellSize + spacing);
        int inset = (width + spacing - numberOfCells * (cellSize + spacing) ) / 2;
    
        return UIEdgeInsetsMake(0, inset, 0, inset);
    }
    

    That code will ensure that the value returned by ...minimumInteritemSpacing... will be the exact spacing between every collectionViewCell and furthermore guarantee that the cells all together will be centered in the collectionView

    0 讨论(0)
  • 2020-11-22 16:34

    I have tried iago849's answer and it worked.

    Swift 4

    open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let answer = super.layoutAttributesForElements(in: rect) else {
            return nil
        }
        let count = answer.count
        for i in 1..<count {
            let currentLayoutAttributes = answer[i]
            let prevLayoutAttributes = answer[i-1]
            let origin = prevLayoutAttributes.frame.maxX
            if (origin + CGFloat(spacing) + currentLayoutAttributes.frame.size.width) < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x {
                var frame = currentLayoutAttributes.frame
                frame.origin.x = origin + CGFloat(spacing)
                currentLayoutAttributes.frame = frame
            }
        }
        return answer
    }
    

    Here is the link for the github project. https://github.com/vishalwaka/MultiTags

    0 讨论(0)
提交回复
热议问题