Search code examples
iosswiftuicollectionviewuicollectionviewcellindexpath

Set a circle label for a separate Cell of CollectionView [Swift]


I'm trying to draw a circle for a visible cell of CollectionView, look like this

enter image description here

I tried to make it trough addSubview and then removeFromSuperview the previous label, but it doesn't work

let myIndex1 = IndexPath(row: 0, section: 0)
    let myIndex2 = IndexPath(row: 1, section: 0)
if indexPath.row == 0 {

    collectionView.cellForItem(at:myIndex1)?.addSubview(labelNew)
            labelNew.layer.backgroundColor = selectedItem.title.cgColor

        }

        if indexPath.row == 1 {

            labelNew.removeFromSuperview()
            collectionView.cellForItem(at:myIndex2)?.addSubview(labelNew2)
            labelNew2.layer.backgroundColor = selectedItem.title.cgColor

        }

What is the right way to draw a circle around a cell of CollectionView which is in the centre at the moment?


Solution

  • For the library you are using. Add an background image in your cell which will be shown as same size as your collectionView and set it hidden by default. then you need to apply the logic in your scrollViewDidScroll method and show background image for cell which is in centre like:

    let indexPath = IndexPath(item: currentIndex, section: 0)
    if let cell = wheelMenuCollectionView.cellForItem(at: indexPath) as? WheelMenuCollectionViewCell {
        cell.backImage.isHidden = false
    }
    

    And to remove previous cell background image you need to add

    for (index, _) in items.enumerated() {
        if index != currentIndex {
            let oldIndexPath = IndexPath(item: index, section: 0)
            if let cell = wheelMenuCollectionView.cellForItem(at: oldIndexPath) as? WheelMenuCollectionViewCell {
                cell.backImage.isHidden = true
            }
        }
    }
    

    and your scrollViewDidScroll method will look like:

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
        let maxOffset = scrollView.bounds.width - scrollView.contentSize.width
        let maxIndex = CGFloat(self.items.count - 1)
        let offsetIndex = maxOffset / maxIndex
    
        let currentIndex = Int(round(-scrollView.contentOffset.x / offsetIndex)).clamped(to: (0 ... self.items.count-1))
    
        if self.items[currentIndex].id != self.selectedItem.id {
            self.selectedItem = self.items[currentIndex]
        }
    
        let indexPath = IndexPath(item: currentIndex, section: 0)
        if let cell = wheelMenuCollectionView.cellForItem(at: indexPath) as? WheelMenuCollectionViewCell {
            cell.backImage.isHidden = false
        }
    
        for (index, _) in items.enumerated() {
            if index != currentIndex {
                let oldIndexPath = IndexPath(item: index, section: 0)
                if let cell = wheelMenuCollectionView.cellForItem(at: oldIndexPath) as? WheelMenuCollectionViewCell {
                    cell.backImage.isHidden = true
                }
            }
        }
    }
    

    Now to show first cell highlighted when user start the app you need to add

    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
            let indexPath = IndexPath(item: 0, section: 0)
            if let cell = self.wheelMenuCollectionView.cellForItem(at: indexPath) as? WheelMenuCollectionViewCell {
                cell.backImage.isHidden = false
            }
        })
    

    in your viewWillAppear method.

    Check THIS sample project for more info.