UICollectionView Set number of columns

后端 未结 17 1123
执笔经年
执笔经年 2020-11-28 17:28

I just started learning about UICollectionViews. I\'m wondering if anyone knows how to specify the number of columns in a collectionview. The default is set to 3 (iPhone/por

相关标签:
17条回答
  • 2020-11-28 18:07

    Swift 3.0. Works for both horizontal and vertical scroll directions and variable spacing

    Specify number of columns

    let numberOfColumns: CGFloat = 3
    

    Configure flowLayout to render specified numberOfColumns

    if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
        let horizontalSpacing = flowLayout.scrollDirection == .vertical ? flowLayout.minimumInteritemSpacing : flowLayout.minimumLineSpacing
        let cellWidth = (collectionView.frame.width - max(0, numberOfColumns - 1)*horizontalSpacing)/numberOfColumns
        flowLayout.itemSize = CGSize(width: cellWidth, height: cellWidth)
    }
    
    0 讨论(0)
  • 2020-11-28 18:07

    I made a collection layout.

    To make the separator visible, Set the background color of the collection view to gray. One row per section.

    Useage:

    let layout = GridCollectionViewLayout()
    layout.cellHeight = 50 // if not set, cellHeight = Collection.height/numberOfSections
    layout.cellWidth = 50  // if not set, cellWidth = Collection.width/numberOfItems(inSection)
    collectionView.collectionViewLayout = layout
    

    Layout:

    import UIKit
    
    class GridCollectionViewLayout: UICollectionViewLayout {
    
    
    var cellWidth : CGFloat = 0
    var cellHeight : CGFloat = 0
    var seperator: CGFloat = 1
    
    private var cache = [UICollectionViewLayoutAttributes]()
    
    
    
    override func prepare() {
    
        guard let collectionView = self.collectionView else {
            return
        }
    
        self.cache.removeAll()
    
    
    
            let numberOfSections = collectionView.numberOfSections
    
            if cellHeight <= 0
            {
                cellHeight = (collectionView.bounds.height - seperator*CGFloat(numberOfSections-1))/CGFloat(numberOfSections)
            }
    
            for section in 0..<collectionView.numberOfSections {
    
                let numberOfItems = collectionView.numberOfItems(inSection: section)
    
                let cellWidth2 : CGFloat
                if cellWidth <= 0
                {
                    cellWidth2 = (collectionView.bounds.width - seperator*CGFloat(numberOfItems-1))/CGFloat(numberOfItems)
                }
                else
                {
                    cellWidth2 = cellWidth
                }
    
    
                for row in 0..<numberOfItems {
    
    
                    let indexPath = NSIndexPath(row: row, section: section)
    
                    let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
                    attributes.frame = CGRect(x: (cellWidth2+seperator)*CGFloat(row),
                                              y: (cellHeight+seperator)*CGFloat(section),
                                              width: cellWidth2,
                                              height: cellHeight)
    
                    //row_temp.append(attributes)
    
                    self.cache.append(attributes)
                }
                //self.itemAttributes.append(row_temp)
            }
    
    }
    
    override var collectionViewContentSize: CGSize {
    
        guard let collectionView = collectionView else
        {
            return CGSize.zero
        }
    
        if (collectionView.numberOfSections <= 0)
        {
            return collectionView.bounds.size
        }
    
        let width:CGFloat
        if cellWidth <= 0
        {
            width = collectionView.bounds.width
        }
        else
        {
            width = cellWidth*CGFloat(collectionView.numberOfItems(inSection: 0))
        }
    
        let numberOfSections = CGFloat(collectionView.numberOfSections)
        var height:CGFloat = 0
        height += numberOfSections * cellHeight
        height += (numberOfSections - 1) * seperator
    
    
    
        return CGSize(width: width, height: height)
    }
    
    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? {
        return cache[indexPath.item]
    }
    }
    
    0 讨论(0)
  • 2020-11-28 18:09

    Here is the working code for Swift 3, to have a two-columns layout :

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
    
        let nbCol = 2
    
        let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
        let totalSpace = flowLayout.sectionInset.left
            + flowLayout.sectionInset.right
            + (flowLayout.minimumInteritemSpacing * CGFloat(nbCol - 1))
        let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(nbCol))
        return CGSize(width: size, height: size)
    }
    

    Feel free to change "nbCol" to your desired number of columns.

    0 讨论(0)
  • 2020-11-28 18:11

    Updated to Swift 5+ iOS 13

    Collectionview Estimate Size must be none

    Declare margin for cell

    let margin: CGFloat = 10
    

    In viewDidLoad configure minimumInteritemSpacing, minimumLineSpacing, sectionInset

     guard let collectionView = docsColl, let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
    
        flowLayout.minimumInteritemSpacing = margin
        flowLayout.minimumLineSpacing = margin
        flowLayout.sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
    

    UICollectionViewDataSource method sizeForItemAt

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    
        let noOfCellsInRow = 2   //number of column you want
        let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
        let totalSpace = flowLayout.sectionInset.left
            + flowLayout.sectionInset.right
            + (flowLayout.minimumInteritemSpacing * CGFloat(noOfCellsInRow - 1))
    
        let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(noOfCellsInRow))
        return CGSize(width: size, height: size)
    }
    
    0 讨论(0)
  • 2020-11-28 18:13

    CollectionViews are very powerful, and they come at a price. Lots, and lots of options. As omz said:

    there are multiple ways you could change the number of columns

    I'd suggest implementing the <UICollectionViewDelegateFlowLayout> Protocol, giving you access to the following methods in which you can have greater control over the layout of your UICollectionView, without the need for subclassing it:

    • collectionView:layout:insetForSectionAtIndex:
    • collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
    • collectionView:layout:minimumLineSpacingForSectionAtIndex:
    • collectionView:layout:referenceSizeForFooterInSection:
    • collectionView:layout:referenceSizeForHeaderInSection:
    • collectionView:layout:sizeForItemAtIndexPath:

    Also, implementing the following method will force your UICollectionView to update it's layout on an orientation change: (say you wanted to re-size the cells for landscape and make them stretch)

    -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
                                   duration:(NSTimeInterval)duration{
    
        [self.myCollectionView.collectionViewLayout invalidateLayout];
    }
    

    Additionally, here are 2 really good tutorials on UICollectionViews:

    http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12

    http://skeuo.com/uicollectionview-custom-layout-tutorial

    0 讨论(0)
  • 2020-11-28 18:13

    If you are lazy using delegate.

    extension UICollectionView {
        func setItemsInRow(items: Int) {
            if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout {
                let contentInset = self.contentInset
                let itemsInRow: CGFloat = CGFloat(items);
                let innerSpace = layout.minimumInteritemSpacing * (itemsInRow - 1.0)
                let insetSpace = contentInset.left + contentInset.right + layout.sectionInset.left + layout.sectionInset.right
                let width = floor((CGRectGetWidth(frame) - insetSpace - innerSpace) / itemsInRow);
                layout.itemSize = CGSizeMake(width, width)
            }
        }
    }
    

    PS: Should be called after rotation too

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