UICollectionViewDelegateFlowLayout has black portions/areas when adding views to it

40 Views Asked by At

I want to build kind of a split screen. I used UICollectionViewFlowLayout for this.

When I add and remove UIViews to and from the screen I want the screen to be split into portions according to the number of views in the current screen.

So wrote the logic upto 4 UIViews.

If only 1 UIView in the screen, I need that UIView to have full screen. If only 2 UIViews, then take the full width and 1/2 of the screen height. If only 3 UIViews, then take the full width and 1/3 of the screen height. If only 4 UIViews, then take the 1/2 width and 1/2 of the screen height.

It splits the screen correctly. but randomly it shows black blank spaces. I tried to do this in so many ways, but couldn't.

issue

Here is my ViewController code,

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    var collectionView: UICollectionView?
    
    var usrArr: [UIView] = []
    
    let btn: UIButton = {
        let btn = UIButton()
        btn.setTitle("+", for: .normal)
        btn.backgroundColor = .blue
        btn.addTarget(self, action: #selector(addItem), for: .touchUpInside)
        return btn
    }()
    
    @objc func addItem() {
        let view = UIView()
        view.layer.borderWidth = 10
        view.layer.borderColor = UIColor.red.cgColor
        view.backgroundColor = randomColor()
        
        usrArr.append(view)
        
        print("Count: \(usrArr.count)")
        
        collectionView?.reloadData()
        collectionView?.invalidateIntrinsicContentSize()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        
        // set layout
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        
        collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
        collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        
        if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
            layout.estimatedItemSize = .zero
        }
        
        // set delegates
        collectionView?.delegate = self
        collectionView?.dataSource = self
        
        // Setup constraints
        setupUI()
    }
    
    func setupUI() {
        view.addSubview(collectionView ?? UICollectionView())
        collectionView?.translatesAutoresizingMaskIntoConstraints = false
        collectionView?.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        collectionView?.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        collectionView?.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        collectionView?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        
        view.addSubview(btn)
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.widthAnchor.constraint(equalToConstant: 50).isActive = true
        btn.heightAnchor.constraint(equalToConstant: 50).isActive = true
        btn.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
        btn.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20).isActive = true
        
        btn.bringSubviewToFront(view)
        btn.layer.zPosition = 10
    }
    
    // Collection view delegate methods
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return usrArr.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundView = usrArr[indexPath.row]
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        if usrArr.count == 4 {
            print("first")
            return CGSize(width: self.view.safeAreaLayoutGuide.layoutFrame.width / 2, height: self.view.safeAreaLayoutGuide.layoutFrame.height / 2)
        } else if usrArr.count == 3 {
            return CGSize(width: self.view.safeAreaLayoutGuide.layoutFrame.width, height: self.view.safeAreaLayoutGuide.layoutFrame.height / 3)
        } else if usrArr.count == 2 {
            return CGSize(width: self.view.safeAreaLayoutGuide.layoutFrame.width, height: self.view.safeAreaLayoutGuide.layoutFrame.height / 2)
        }
        print("second")
        return CGSize(width: self.view.bounds.width, height: self.view.bounds.height)
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        usrArr.remove(at: indexPath.row)
        print("Count: \(usrArr.count)")
        collectionView.reloadData()
        collectionView.layoutIfNeeded()
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView?.layoutIfNeeded()
    }
    
    func randomColor() -> UIColor {
        let newRed   = Double(arc4random_uniform(256))/255.0
        let newGreen = Double(arc4random_uniform(256))/255.0
        let newBlue  = Double(arc4random_uniform(256))/255.0
        
        return UIColor(red: CGFloat(newRed), green: CGFloat(newGreen), blue: CGFloat(newBlue), alpha: 1.0)
    }
}

0

There are 0 best solutions below