3

I want to create a UICollectionView that has different item size. It is similar to this image.

enter image description here

It is a Vertical UICollectionView.


    class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .white
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical

        let collectionView = CollectionView(frame: .zero, collectionViewLayout: layout)
        view.addSubview(collectionView)
        collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        collectionView.heightAnchor.constraint(equalToConstant: 240).isActive = true
        collectionView.translatesAutoresizingMaskIntoConstraints = false
    }
}


class CollectionView: UICollectionView {
    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        self.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.identifier)
        self.dataSource = self
        self.delegate = self
        self.isPagingEnabled = true

    }

    required init?(coder: NSCoder) {
        fatalError()
    }

}

extension CollectionView: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier, for: indexPath) as! CollectionViewCell
        cell.backgroundColor = .blue
        cell.label.text = "\(indexPath.row)"

        let row = indexPath.row
        switch row {
        case 0:
            cell.backgroundColor = .red
        case 1:
            cell.backgroundColor = .blue
        case 2:
            cell.backgroundColor = .purple
        case 3:
            cell.backgroundColor = .orange
        case 4:
            cell.backgroundColor = .cyan
        case 5:
            cell.backgroundColor = .green
        case 6:
            cell.backgroundColor = .magenta
        default:
            cell.backgroundColor = .systemPink
        }
        return cell
    }


}

extension  CollectionView: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let row = indexPath.row
        let width = collectionView.frame.width
        let other = width / 3

        let height = collectionView.frame.height
        let o_height =  height / 3
        switch row {
        case 0:
            return CGSize(width: other * 2, height: o_height * 2)
        case 1, 2, 5:
            return CGSize(width: other, height: o_height)
        case 3:
            return CGSize(width: other, height: o_height)
        case 4:
            return CGSize(width: other, height: o_height)
        default:
            return CGSize(width: width, height: height)
        }
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return .leastNormalMagnitude
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return .leastNormalMagnitude
    }
}



class CollectionViewCell: UICollectionViewCell {
    static let identifier = "CollectionViewCell"

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.contentView.addSubview(label)
        label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
        label.translatesAutoresizingMaskIntoConstraints = false
    }

    required init?(coder: NSCoder) {
        fatalError()
    }
}

I have used the above code. It does not work: the second item is not in the correct position: there are empty space before and afte of it. As a result, the rest of the items are pushed down.

enter image description here

Thanks in advance!


Update

It works if I use horizontal scroll and change width of item 1.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let row = indexPath.row
    let width = collectionView.frame.width
    let other = width / 3

    let height = collectionView.frame.height
    let o_height =  height / 3
    switch row {
    case 0:
        return CGSize(width: other * 2, height: o_height * 2)
    case 1:
            return CGSize(width: other * 2, height: o_height)
    case 2:
        return CGSize(width: other, height: o_height)
    case 3:
        return CGSize(width: other, height: o_height)
    case 4:
        return CGSize(width: other, height: o_height)
    default:
        return CGSize(width: width, height: height)
    }
} 
mahan
  • 12,366
  • 5
  • 48
  • 83
  • best you can make your own UICollectionViewLayout – Charlie Cai Jun 10 '20 at 13:12
  • Have you tried `layout.invalidateLayout()` in `viewDidLayoutSubviews()` ? – Omer Tekbiyik Jun 10 '20 at 13:44
  • @OmerTekbiyik Yes. Still the same issue. – mahan Jun 10 '20 at 14:08
  • Could using number of sections = 2 be an option for you? – luckystars Jun 10 '20 at 17:32
  • You need a custom layout. Default Layout won't be able to to so. As you see, you can put only one item per "line". You can put the big one, and two above the other (1 & 2) in the same "line". You can check https://stackoverflow.com/questions/43186246/uicollectionview-layout-like-snapchat – Larme Jun 11 '20 at 09:24
  • @mahan: I have tried above working Good. But only one issue is there, that is index 1 coming full horizontally. Can we split it to Two columns? then everything is good https://ibb.co/gwYwNWb – Priya Jun 11 '20 at 11:15
  • @Priya combine 1 & 2 in 1 – mahan Jun 11 '20 at 12:22
  • @mahan: how to combine 1 & 2 in 1.Can you please update in above – Priya Jun 11 '20 at 12:42
  • @Priya Add two views that has same width in cell 1. Bescically instead of item 1 and 2, use 1 cell that contains both. I think this is the cleanest way to fix your issue. – mahan Jun 11 '20 at 13:09
  • @mahan: How to devide cell 1 into Cell1 and Cell2 – Priya Jun 11 '20 at 14:49
  • @mahan : Any Solution for my question. https://stackoverflow.com/q/62130759/6285383 – Priya Jun 12 '20 at 09:41

0 Answers0