uicollectionviewcelluicollectionviewlayoutmixinguicollectionviewflowlayout

Swift UICollectionViewCell Item Mixing... Video of the problem is available


My problem video: https://streamable.com/2vrdbu

As you move around the "Collection View" the objects move around and the assignment doesn't work properly.

I tried many methods, but I could not achieve successful results.

Code blocks:

UIViewController:

class BeadsViewController: UIViewController {

    
    
    private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 10
        layout.sectionInset = .init(top: 0, left: 0, bottom: 0, right: 0)
        return layout
    }()
    
    
    private lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.register(BeadsCell.self, forCellWithReuseIdentifier: BeadsCell.reuseID)
        collectionView.backgroundColor = .clear
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.showsVerticalScrollIndicator = false
        return collectionView
        
    }()

Extension for CollectionView

Extension View Controller: (UICollectionViewCell Delegate etc.)

extension BeadsViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return beadsList.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let item = collectionView.dequeueReusableCell(withReuseIdentifier: BeadsCell.reuseID, for: indexPath) as! BeadsCell
        incomingIndex = indexPath.item + 1
        let beads = beadsList[indexPath.item]
        item.setGenerate(item: Beads(imageName: beads.imageName, isPremium: beads.isPremium))
        return item
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width: CGFloat = (collectionViewWidth - 38) / CGFloat(3)
        let height: CGFloat
        switch screenHeight {
        case 667: // SE 2nd gen, 8, 7, 6s, 6
            height = (160 * screenHeight) / 926
        case 736: // 8 plus
            height = (150 * screenHeight) / 926
        default:
            height = (163 * screenHeight) / 926 // 13 pro max - 12 pro max
        }
        return CGSize(width: width, height: height)
    }
}

Cell:

class BeadsCell: UICollectionViewCell {

static let reuseID = "beadsCell"


lazy var backgroundArea: UIImageView = {
    let bgArea = UIImageView()
    bgArea.layer.cornerRadius = 10
    bgArea.image = UIImage(named: "lockBeadBG")?.withRenderingMode(.alwaysOriginal)
    return bgArea
}()

lazy var imageArea: UIImageView = {
    let imageArea = UIImageView()
    imageArea.contentMode = .scaleAspectFit
    return imageArea
}()

lazy var lockImage: UIImageView = {
    let imageArea = UIImageView()
    imageArea.contentMode = .scaleAspectFit
    imageArea.image = UIImage(named: "lockImage")?.withRenderingMode(.alwaysOriginal)
    return imageArea
}()


lazy var openImage: UIImageView = {
    let imageArea = UIImageView()
    imageArea.contentMode = .scaleAspectFit
    imageArea.image = UIImage(named: "unlcokBtn")?.withRenderingMode(.alwaysOriginal)
    return imageArea
}()

lazy var openText: UILabel = {
    let label = UILabel()
    label.text = "Open"
    label.textColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
    label.font = UIFont(name: "CeraPro-Bold", size: 15.2)
    return label
}()

func setGenerate(item: Beads) {
    if(item.isPremium == false){
        imageArea.image = UIImage(named: item.imageName!)?.withRenderingMode(.alwaysOriginal)
    } else if (item.isPremium == true) {
        imageArea.image = UIImage(named: item.imageName!)?.withRenderingMode(.alwaysOriginal)
    }
}


lazy var screenHeight = UIScreen.main.bounds.height
lazy var screenWidth = UIScreen.main.bounds.width

func beadsCellLayout(){
        addSubview(backgroundArea)
        if (beadsList[incomingIndex].isPremium == false) {
            backgroundArea.anchor(top: contentView.topAnchor, bottom: contentView.bottomAnchor, leading: contentView.leadingAnchor, trailing: contentView.trailingAnchor, size: .init(width: (120 * screenWidth / 428), height: (163 * screenHeight / 926)))
            backgroundArea.addSubview(imageArea)
            imageArea.anchor(top: nil, bottom: nil, leading: nil, trailing: nil, size: .init(width: (75 * screenWidth / 428 ), height: (75 * screenHeight / 926)))
            imageArea.centerXAnchor.constraint(equalTo: backgroundArea.centerXAnchor).isActive = true
            imageArea.centerYAnchor.constraint(equalTo: backgroundArea.centerYAnchor).isActive = true
        } else {
            backgroundArea.anchor(top: contentView.topAnchor, bottom: contentView.bottomAnchor, leading: contentView.leadingAnchor, trailing: contentView.trailingAnchor, size: .init(width: (120 * screenWidth / 428), height: (163 * screenHeight / 926)))
            backgroundArea.addSubview(imageArea)
            imageArea.anchor(top: backgroundArea.topAnchor, bottom: nil, leading: nil, trailing: nil, padding: .init(top: 25, left: 0, bottom: 0, right: 0))
            imageArea.centerXAnchor.constraint(equalTo: backgroundArea.centerXAnchor).isActive = true
            backgroundArea.addSubview(lockImage)
            lockImage.anchor(top: nil, bottom: nil, leading: imageArea.leadingAnchor, trailing: nil, padding: .init(top: 0, left: (22 * screenWidth / 428), bottom: 0, right: 0))
            lockImage.centerYAnchor.constraint(equalTo: imageArea.centerYAnchor).isActive = true
            backgroundArea.addSubview(openImage)
            openImage.anchor(top: nil, bottom: backgroundArea.bottomAnchor, leading: nil, trailing: nil, padding: .init(top: 0, left: 0, bottom: 10, right: 0))
            openImage.centerXAnchor.constraint(equalTo: backgroundArea.centerXAnchor).isActive = true
            openImage.addSubview(openText)
            openText.anchor(top: openImage.topAnchor, bottom: nil, leading: openImage.leadingAnchor, trailing: nil, padding: .init(top: 13, left: 40, bottom: 0, right: 0))
        }
}

override init(frame: CGRect) {
    super.init(frame: frame)
    beadsCellLayout()
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

/*override func prepareForReuse() {
    //super.prepareForReuse()
    backgroundArea.image = nil
    imageArea.image = nil
    lockImage.image = nil
    openImage.image = nil
    openText.text = nil

}*/

}

Solution

  • In this case, you should use two different cells for the collectionview.

    One for current cells and one for premium ones