Lynx
Lynx

Reputation: 401

How to set a interval between two photos in UICollecetionView on iOS with Swift?

I want to achieve an effect that the photos occupy all the screen, and when scrolling the photos in the album, there will be an interval between the two photos, and the photos will automatically bounce back to the center after sliding.

I set minimumLineSpacing and isPagingEnabled, but when I swipe, the image doesn't fill the entire screen, instead, the left side shows the spacing.

Does anyone know how to achieve this?

Code:

layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 10
view.addSubview(mCollectionView)
mCollectionView.isPagingEnabled = true
mCollectionView.backgroundColor = .white
mCollectionView.register(UINib(nibName: "PhotoDetailCVCell", bundle: nil), forCellWithReuseIdentifier: cvCellIdentifier)
mCollectionView.snp.makeConstraints { (make) in
    make.edges.equalTo(view)
}

Target effect:

When it's at rest:

At rest

When we move it:

When sliding

And the current style while still is:

current style

Upvotes: 1

Views: 108

Answers (2)

Lynx
Lynx

Reputation: 401

It confuses me for days and I found the solution in the end. The solution is simple. The isPagingEnabled is decided by the frame of the collectionView so what we need is to make the size of the collectionView large than the frame of the window. We can just set the minimumLineSpacing and set the layout of collectionView so that it would stretch out to the right. Then we will get a interval between two cells and the page just works well.

Here is the code:

layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 10
view.addSubview(mCollectionView)
mCollectionView.isPagingEnabled = true
mCollectionView.backgroundColor = .white
mCollectionView.register(UINib(nibName: "PhotoDetailCVCell", bundle: nil), forCellWithReuseIdentifier: cvCellIdentifier)
mCollectionView.snp.makeConstraints { (make) in
    make.left.top.bottom.equalToSuperview()
    make.right.equalToSuperview().offset(10)
}

Upvotes: 0

DonMag
DonMag

Reputation: 77690

Here is one approach - it may or may not fit your needs...

For your cell layout, give the image view 5-pts "padding" on each side:

enter image description here

When the cells are adjacent (with flow layout set to .minimumLineSpacing = 0 and .minimumInteritemSpacing = 0), the visual result will make it look like there is 10-pts of spacing between the images:

enter image description here

Next, layout the collection view so it is 10-pts wider than the controller's view:

enter image description here

As you drag, it will appear that we have 10-pts of spacing between the cells:

enter image description here

and .isPagingEnabled = true will "snap" the cell into place:

enter image description here

Here is a complete example - Note: This is Sample Code Only!!

Basic cell class with a UIImageView:

class PhotoDetailCVCell: UICollectionViewCell {
    
    let imgView: UIImageView = {
        let v = UIImageView()
        v.contentMode = .scaleAspectFit
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        
        contentView.addSubview(imgView)

        // constrain image view
        imgView.snp.makeConstraints { (make) in
            //  top/bottom
            make.top.bottom.equalTo(contentView)
            //  leading/trailing inset by 5-pts
            make.leading.trailing.equalTo(contentView).inset(5.0)
        }

    }
    
}

Example controller class:

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    
    let cvCellIdentifier: String = "photoCVCell"
    
    var mCollectionView: UICollectionView!
    
    var imgNames: [String] = [
        "p1", "p2", "p3", "p4", "p5",
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let layout = UICollectionViewFlowLayout()
        
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        
        mCollectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        mCollectionView.isPagingEnabled = true
        mCollectionView.backgroundColor = .white

        view.addSubview(mCollectionView)
        
        // respect safe area
        mCollectionView.snp.makeConstraints { (make) in
            // top/bottom equal to safe area
            make.top.bottom.equalTo(view.safeAreaLayoutGuide)
            // leading/trailing equal to safe area inset by -5.0
            //  this makes the collection view 10-pts WIDER than the view
            //  so having 5-pts "spacing" on each side of the cell's imageView
            //  will give the appearance of 10-pts spacing between cells
            make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(-5.0)
        }

        // if you're using a XIB for your cell
        //mCollectionView.register(UINib(nibName: "PhotoDetailCVCell", bundle: nil), forCellWithReuseIdentifier: cvCellIdentifier)
        
        // if you're using code (as in this example) for your cell
        mCollectionView.register(PhotoDetailCVCell.self, forCellWithReuseIdentifier: cvCellIdentifier)
        
        mCollectionView.dataSource = self
        mCollectionView.delegate = self
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        // set collection view itemSize here, since we now know
        //  the frame size of the collection view
        if let layout = mCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            layout.itemSize = mCollectionView.frame.size
        }
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imgNames.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cvCellIdentifier, for: indexPath) as! PhotoDetailCVCell
        
        // try to load the image from Assets
        if let img = UIImage(named: imgNames[indexPath.item]) {
            cell.imgView.image = img
        } else {
            // could not  load image from Assets, so create a systemName image
            if let img = UIImage(systemName: "\(indexPath.item).square.fill") {
                cell.imgView.image = img
            }
        }
        
        // set image view background color if you want to see its frame
        //cell.imgView.backgroundColor = .lightGray

        return cell
    }
    
}

Upvotes: 3

Related Questions