Search code examples
iosswiftuicollectionviewuicollectionviewcellreusability

SubViews are not adding in some UICollectionViewCells and flickering (programmatically)


I am trying to make custom Image Slider with collections view. I want to it to be reusable. So I made separate custom class where all collectionView stuff. and then call that class from UIViewController as shown in code below. And my UICollectonViewCell only contains imageView.

Problem is that in second cell. imageView is not being added and on third cell, it also flickers. I tried to debug these issues but could not.

ImageSlider class and UICollectionViewCell class at end end, with collection view stuff:

class ImageSlider: UIView {
    var imgArr = [UIImage(named: "one.jpg"), UIImage(named: "3.jpg"), UIImage(named: "two.jpg"), UIImage(named: "4.jpg")]
    var sliderCollection : UICollectionView = {
        let widthRatio : Float = 16.0
        let heightRatio : Float = 9.0
        let collecionWidth = UIScreen.main.bounds.width - 30
        let layout = UICollectionViewFlowLayout()
        let collectionView = UICollectionView(frame: CGRect(x: 15, y: 100, width: collecionWidth, height: CGFloat((Float(collecionWidth)*heightRatio)/widthRatio)), collectionViewLayout: layout)
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        collectionView.backgroundColor = .systemOrange
        collectionView.isPagingEnabled = true
//        collectionView.isScrollEnabled = true
        collectionView.register(ImageSliderCell.self, forCellWithReuseIdentifier: "ImageSliderCell")
        return collectionView
    }()
    
    
}

extension ImageSlider: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imgArr.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageSliderCell", for: indexPath) as! ImageSliderCell
        
        cell.imgView.image = imgArr[indexPath.item]
//        cell.imgView.contentMode = .scaleAspectFit
        print("cell frame : ", "(\(cell.frame.width), \(cell.frame.height)")
        print("imgView frame : ", "(\(cell.imgView.frame.width), \(cell.imgView.frame.height)")
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
    }
    
}

class ImageSliderCell: UICollectionViewCell {
    var imgView = UIImageView()
    
//    override func awakeFromNib() {
//        self.addSubview(imgView)
//    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        imgView.frame = frame
        self.addSubview(imgView)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

This is ViewController, where I am calling ImageSlider() class.

class ImageSliderVC: UIViewController, UICollectionViewDelegate {
    
    let imageSlider = ImageSlider()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(imageSlider.sliderCollection)
        imageSlider.sliderCollection.delegate = imageSlider
        imageSlider.sliderCollection.dataSource = imageSlider
        imageSlider.sliderCollection.reloadData()
    }
}

Solution

  • It looks like it does not work without constrains because UICollectionViewCell could be created with zero frame and it translated to imageView inside the cell. You need to add constrains to imageView to make it visible.

    extension UIView {
        
        func centerX(inView view: UIView, constant: CGFloat = 0) {
            translatesAutoresizingMaskIntoConstraints = false
            centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: constant).isActive = true
        }
        
        func centerY(inView view: UIView, constant: CGFloat = 0) {
            translatesAutoresizingMaskIntoConstraints = false
            centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: constant).isActive = true
        }
        
        func setDimensions(height: CGFloat, width: CGFloat) {
            translatesAutoresizingMaskIntoConstraints = false
            heightAnchor.constraint(equalToConstant: height).isActive = true
            widthAnchor.constraint(equalToConstant: width).isActive = true
        }
        
        func setHeight(_ height: CGFloat) {
            translatesAutoresizingMaskIntoConstraints = false
            heightAnchor.constraint(equalToConstant: height).isActive = true
        }
    }
    
    class ImageSliderCell: UICollectionViewCell {
        var imgView = UIImageView()
        
        
        override init(frame: CGRect) {
            super.init(frame: frame)
      
            self.addSubview(imgView)
            // not sure about the right size of image ...
            imgView.setDimensions(height: 100.0, width: 100.0)
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }