Agung
Agung

Reputation: 13843

how to make expandable collection view in swift?

enter image description here

I have 2 collection view sections, when this VC is loaded in the first time, both of sections (indoor and outdoor) initially will show just 3 items.

But after the user press "More" button, each section either indoor or outdoor will expand and show up all items available, like the picture below

enter image description here

I have tried to make the code, but it seems sometimes it can expand and sometimes it doesn't expand (still show 3 items).

Here is the code in the main controller:

class FacilitiesVC: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!

    var facilitiesCategoryData = [[String:Any]]()
    var outdoorFacilitiesIsExpanded = false
    var indoorFacilitiesIsExpanded = false

    override func viewDidLoad() {
        super.viewDidLoad()

        getIndoorOutdoorFacilitiesData()
    }

}

extension FacilitiesVC {

    // MARK: - Helper Methods

    func getIndoorOutdoorFacilitiesData() {

        let facilitiesData = FacilitiesCategoryLibrary.fetchFacilitiesCategory()
        var indoorFacilities = [FacilitiesCategory]()
        var outdoorFacilities = [FacilitiesCategory]()

        // distinguishing between indoor and outdoor data
        for facData in facilitiesData {

            if facData.type == "Indoor Facility" {
                indoorFacilities.append(facData)
            } else {
                outdoorFacilities.append(facData)
            }
        }

        facilitiesCategoryData = [
            ["title": "Indoor Facilities", "info": indoorFacilities],
            ["title": "Outdoor Facilities", "info": outdoorFacilities]
        ]
    }

}

extension FacilitiesVC: UICollectionViewDataSource {

    // MARK: - UICollectionViewDataSource

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return facilitiesCategoryData.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        if section == 0 {

            if indoorFacilitiesIsExpanded {
                let category = facilitiesCategoryData[section]
                let infoList = category["info"] as! [FacilitiesCategory]
                return infoList.count
            } else {
                return 3
            }

        } else {

            if outdoorFacilitiesIsExpanded {
                let category = facilitiesCategoryData[section]
                let infoList = category["info"] as! [FacilitiesCategory]
                return infoList.count
            } else {
                return 3
            }

        }
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: StoryBoard.facilitiesCategoryCellIdentifier, for: indexPath) as! FacilitiesCell

        let category = facilitiesCategoryData[indexPath.section]
        let infoList = category["info"] as! [FacilitiesCategory]
        cell.facilitiesCategoryData = infoList[indexPath.item]

        return cell
    }

    // for section header view
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

        let sectionHeaderView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: StoryBoard.facilitiesSectionHeaderIdentifier, for: indexPath) as! FacilitiesSectionHeader

        let category = facilitiesCategoryData[indexPath.section]
        sectionHeaderView.categoryData = category
        sectionHeaderView.sectionHeaderDelegate = self

        return sectionHeaderView
    }

}

extension FacilitiesVC: FacilitiesSectionHeaderDelegate {

    func didPressButton(_ facilities: String, isExpanded: Bool) {

        if facilities == "Indoor Facilities" {
            indoorFacilitiesIsExpanded = isExpanded
        } else if facilities == "Outdoor Facilities" {
            outdoorFacilitiesIsExpanded = isExpanded
        }

        collectionView.reloadData()
    }

}

and here is the code in the collection view section header

import UIKit

protocol FacilitiesSectionHeaderDelegate: class {
    func didPressButton(_ facilities: String, isExpanded: Bool)
}

class FacilitiesSectionHeader: UICollectionReusableView {

    @IBOutlet weak var titleLabel: UILabel!

    weak var sectionHeaderDelegate: FacilitiesSectionHeaderDelegate?

    var collectionIsExpanded = false
    var facilitiesType = ""

    var categoryData: [String:Any]! {
        didSet {
            titleLabel.text = categoryData["title"] as? String
            facilitiesType = categoryData["title"] as! String
        }
    }

    @IBAction func moreButtonDidPressed(_ sender: Any) {
        collectionIsExpanded = !collectionIsExpanded
        sectionHeaderDelegate?.didPressButton(facilitiesType, isExpanded: collectionIsExpanded)
    }

}

maybe I make mistake in collection numberOfItemsInSection, in this lines of code

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    if section == 0 {

        if indoorFacilitiesIsExpanded {
            let category = facilitiesCategoryData[section]
            let infoList = category["info"] as! [FacilitiesCategory]
            return infoList.count
        } else {
            return 3
        }

    } else {

        if outdoorFacilitiesIsExpanded {
            let category = facilitiesCategoryData[section]
            let infoList = category["info"] as! [FacilitiesCategory]
            return infoList.count
        } else {
            return 3
        }

    }
}

I thought that that section argument parameter is the same as indexPath.section , but it seems different, but I don't know how to access indexPath.section from collection numberOfItemsInSection method

how to fix that?

Upvotes: 3

Views: 7221

Answers (1)

Shehata Gamal
Shehata Gamal

Reputation: 100533

You have to assign current state inside viewForSupplementaryElementOfKind

 func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

    let sectionHeaderView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: StoryBoard.facilitiesSectionHeaderIdentifier, for: indexPath) as! FacilitiesSectionHeader

    let category = facilitiesCategoryData[indexPath.section]
    sectionHeaderView.categoryData = category
    sectionHeaderView.sectionHeaderDelegate = self

    if(indexPath.section == 0)
    {
       sectionHeaderView.collectionIsExpanded =  indoorFacilitiesIsExpanded
    }
    else
    {
      sectionHeaderView.collectionIsExpanded = outdoorFacilitiesIsExpanded
    }

    return sectionHeaderView
}

As inside FacilitiesSectionHeader you flip according to it

 @IBAction func moreButtonDidPressed(_ sender: Any) {

    collectionIsExpanded = !collectionIsExpanded
    sectionHeaderDelegate?.didPressButton(facilitiesType, isExpanded: collectionIsExpanded)

}

Upvotes: 3

Related Questions