0

I have a horizontal UICollectionView with green background (attached image) and I`d like to adjust its width depending on how many cells are available. After that, the button needs to be attached to collection views trailing anchor

For example: I have one photo in collection view, and its view width is 100. User pressed button, added photo to the collection, and width, increased to 200. Therefore addImageButton has moved to the right.

It should look something like this:

resizable collection view

My current code is this:

class ImagesViewController: UIViewController {
    
    lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 8
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.register(ImagesCollectionViewCell.self, forCellWithReuseIdentifier: ImagesCollectionViewCell.reuseIdentifier)
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        return collectionView
    }()
    
    lazy var addImageButton: UIButton = {
        let btn = UIButton()
        btn.layer.cornerRadius = 8
        btn.clipsToBounds = true
        btn.contentMode = .scaleAspectFill
        btn.backgroundColor = Colors.tintDefault
        btn.setImage(UIImage(named: "addImage"), for: .normal)
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.addTarget(self, action: #selector(handleAddImage), for: .touchUpInside)
        return btn
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = Colors.backgroundPrimary
        
        [collectionView, addImageButton].forEach { view.addSubview ($0) }
        
        collectionView.anchor(top: top.bottomAnchor, leading: view.leadingAnchor, paddingTop: 20, width: 272, height: 80)
        collectionView.backgroundColor = .green
        
        addImageButton.centerYAnchor.constraint(equalTo: collectionView.centerYAnchor).isActive = true
        addImageButton.anchor(leading: collectionView.trailingAnchor, paddingLeft: 32, width: 24, height: 24)
        
        
    }
}

extension ImagesViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    // Some code here... (numberOfItemsInSection, cellForItemAt, etc)
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 80, height: 80)
    }
    
}

Please read the question carefully!

Dynamic collectionView width is needed, not the cell width!

Please help me out to set dynamic width for collection view

Russ
  • 53
  • 1
  • 9
  • Simply put that + icon as a new cell and don't play with the width of the collection view. That's it. Also if you put + as first row of collection view is good for UX. – Fahim Parkar Jul 04 '21 at 06:02
  • Can you have 4-5 OR 10 images there? What should happen if the number of images can not fit in current width? Does it scroll horizontally or do the new images appear on the next row vertically? – Tarun Tyagi Jul 04 '21 at 06:07
  • @FahimParkar thank you very much for your advice. Ive been thinking about this option too (or add + icon as collection view footer). But in that case I`ll have to use closures or delegate to open up the image picker – Russ Jul 04 '21 at 06:17
  • @TarunTyagi nope, the maximum number of photos is 3. So its just one row of photos and + button next to them – Russ Jul 04 '21 at 06:19
  • @Russ : Ok, where is the problem? It's same as button click. This way, its easy even if you have 3+ rows. Anyway, choice is yours. – Fahim Parkar Jul 04 '21 at 11:26

1 Answers1

2

Try following :

  1. Declare a variable inside your UIViewController subclass like this.
private var contentSizeObservation: NSKeyValueObservation?
  1. Inside viewDidLoad() or whenever your myCollectionView is set up, start observing contentSize changes.
contentSizeObservation = myCollectionView.observe(\.contentSize, options: .new, changeHandler: { [weak self] (cv, _) in
    guard let self = self else { return }
    self.myCollectionViewWidthConstraint.constant = cv.contentSize.width
})
  1. Do NOT Forget to clean this up in deinit call -
deinit {
    contentSizeObservation?.invalidate()
}

This approach will make sure that your myCollectionView is always as big in width as it's content.

Tarun Tyagi
  • 9,364
  • 2
  • 17
  • 30