skip to Main Content

I wanted to make indefinite UICollectionViewCell that moves to another row once it’s exceed the width of my UICollectionView. Here’s the picture of what I’m trying to achieve.

enter image description here

As you can see, each width of the cell is resizing based on the content inside. The next cell will go horizontally, then after that it create another row if it exceed the width.

Here’s my UICollectionView:

    var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .vertical
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
    collectionView.backgroundColor = .white
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    collectionView.backgroundColor = MSColorFoundation.msClear
    return collectionView
}()

Here’s my UICollectionViewLayoutDelegate:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let noOfCellsInRow = 3

    let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout

    let totalSpace = (flowLayout?.sectionInset.left ?? 0.0)
    + (flowLayout?.sectionInset.right ?? 0.0)
    + ((flowLayout?.minimumInteritemSpacing ?? 0.0) * CGFloat(noOfCellsInRow - 1))

    let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(noOfCellsInRow))

    return CGSize(width: size, height: 60)
}

2

Answers


  1. From what I can see in your code, the sizeForItemAt function will always create cells in a way that your collection view will always have 3 cells in a row. I would suggest you to omit your sizeForItemAt function and create a simple Xib cell. Take a label in you Xib and then give your label a leading and trailing constant then register that Xib to your collection view. This will make your every cell to automatically depend on its label and infer its width from its label.

    Login or Signup to reply.
  2. It sounds like you want to implement a UICollectionView with cells that flow from left to right, wrapping to the next row when they exceed the width of the collection view. This can be achieved using the UICollectionViewFlowLayout, which is a built-in layout class provided by UIKit.

    To create a UICollectionViewFlowLayout that flows cells from left to right and wraps to the next row, you can set the scroll direction to horizontal and adjust the minimumInteritemSpacing and minimumLineSpacing properties as needed.

    class MyCollectionViewController: UICollectionViewController {
        // Set up the collection view flow layout
        let flowLayout = UICollectionViewFlowLayout()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Configure the flow layout
            flowLayout.scrollDirection = .horizontal
            flowLayout.minimumInteritemSpacing = 10
            flowLayout.minimumLineSpacing = 10
            collectionView.collectionViewLayout = flowLayout
    
            // Register your custom UICollectionViewCell subclass
            collectionView.register(MyCustomCell.self, forCellWithReuseIdentifier: "MyCustomCell")
            }
    
            // Implement the UICollectionViewDataSource methods to provide the data for your cells
            override func numberOfSections(in collectionView: UICollectionView) -> Int {
                return 1
            }
    
            override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            // Return the number of items in your data source
            return myData.count
            }
    
            override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCustomCell", for: indexPath) as! MyCustomCell
    
                // Configure the cell with data from your data source
                cell.configure(with: myData[indexPath.item])
    
                return cell
            }
        }
    

    In your custom UICollectionViewCell subclass, you can set the autoresizingMask property to allow the cell to resize itself as needed when the collection view width changes

    class MyCustomCell: UICollectionViewCell {
        let label = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    
        // Set up the cell's subviews
        label.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(label)
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: contentView.topAnchor),
            label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
    
        // Configure the label's appearance
        label.textAlignment = .center
        label.textColor = .white
        label.backgroundColor = .blue
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configure(with text: String) {
        label.text = text
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
    
        // Allow the cell to resize itself as needed when the collection view width changes
        contentView.autoresizingMask = [.flexibleWidth]
    }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search