swiftuicollectionviewinstagramsegmentedcontrol

How to dynamically change a collectionView Item size (like instagram) using segmented control


How can I build a UICollectionView similar to the Instagram one? I already created the three columns one:

let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    let width = (view.frame.width/3)-2

    myCollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    layout.sectionInset = UIEdgeInsets(top: 49, left: 1, bottom: 1.5, right: 1)
    layout.itemSize = CGSize(width: width, height: width)
    layout.minimumInteritemSpacing = 1
    layout.minimumLineSpacing = 1

    myCollectionView?.dataSource = self
    myCollectionView?.delegate = self
    myCollectionView?.register(PhotoGalleryCell.self, forCellWithReuseIdentifier: cellid)
    myCollectionView?.backgroundColor = .white
    self.view.addSubview(myCollectionView!)

    myCollectionView!.addSubview(segmentedControl)
    segmentedControl.topAnchor.constraint(equalTo: myCollectionView!.topAnchor, constant: 12).isActive = true
    segmentedControl.centerXAnchor.constraint(equalTo: myCollectionView!.centerXAnchor).isActive = true
    segmentedControl.heightAnchor.constraint(equalToConstant: 25).isActive = true
    segmentedControl.widthAnchor.constraint(equalTo: myCollectionView!.widthAnchor, constant: -24).isActive = true

But I want the Collection view's items to become a 1 column width when the selectedControl's value becomes 1, and then if the value goes back to 0 the collectionView goes back to a 3 columns setup. Is there a way to do this?


Solution

  • You need to change the layout of the collectionView based on the expected UI - grid or list, when switching between the segments of UISegmentedControl.

    First of all, create an enum LayoutType like,

    enum LayoutType {
        case list, grid
    }
    

    Now, in your ViewController, create a property layoutType of type LayoutType initially set to .list, i,e.

    var layoutType = LayoutType.list
    

    Next, implement the @IBAction for segmentedControl's valueChanged event. So, till now the ViewController looks like.

    class VC: UIViewController, UICollectionViewDelegateFlowLayout {
        @IBOutlet weak var collectionView: UICollectionView!
        var layoutType = LayoutType.list
    
        @IBAction func onChange(_ sender: UISegmentedControl) {
            if sender.selectedSegmentIndex == 0 {
                layoutType = .list
            } else {
                layoutType = .grid
            }
            collectionView.reloadData()
        }
    }
    

    Now implement the UICollectionViewDataSource methods as required. You must've done that already.

    Now to change the layout based on the layoutType, you need to conform to UICollectionViewDelegateFlowLayout protocol and implement the below methods,

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        switch layoutType {
        case .list:
            return CGSize(width: collectionView.bounds.width, height: 50)
        case .grid:
            return CGSize(width: (collectionView.bounds.width - 20) / 3, height: 50)
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 10
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 10
    }
    

    This is how you can proceed with the things. Let me know in case you still face any issue.