Check if cell completely displayed in collectionvi

2019-08-27 22:17发布

问题:

I have a collection view where the cell is of the size exactly to the collectionView, so each cell should occupy the whole screen. I have implemented a functionality where the cell is snapped to the complete view whenever it's dragged or decelerated through the scroll. This is how the UX works.

https://drive.google.com/open?id=1v8-WxCQUzfu8V_k9zM1UCWsf_-Zz4dpr

What I want:

As you can see from the clip, the cell snaps to the whole screen. Now, I want to execute a method after it snaps. Not before or not when it's partially displayed.

Following is the code I have written for snapping effect :

func scrollToMostVisibleCell(){
    let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
    let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
    let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint)!
    collectionView.scrollToItem(at: visibleIndexPath as IndexPath, at: .top, animated: true)
    print("cell is ---> ", visibleIndexPath.row)
}



func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    scrollToMostVisibleCell()
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    scrollToMostVisibleCell()
    if !decelerate {
        scrollToMostVisibleCell()
    }
}

If I use willDisplayCell method, then it' just going to return me as soon as the cell is in the view, even if it's just peeping in the collectionView.

Is there a way where I can check if the cell is completely in the view and then I can perform a function?

I have scrapped the internet over this question, but ain't able to find a satisfactory answer.

回答1:

Using followedCollectionView.indexPathsForVisibleItems() to get visible cells visibleIndexPaths and check your indexPath is contained in visibleIndexPaths or not, before doing anything with cells. Ref : @anhtu Check whether cell at indexPath is visible on screen UICollectionView

Also from Apple : var visibleCells: [UICollectionViewCell] { get } . Returns an array of visible cells currently displayed by the collection view.



回答2:

Here is a complete example of a "full screen" vertical scrolling collection view controller, with paging enabled (5 solid color cells). When the cell has "snapped into place" it will trigger scrollViewDidEndDecelerating where you can get the index of the current cell and perform whatever actions you like.

Add a new UICollectionViewController to your storyboard, and assign its class to VerticalPagingCollectionViewController. No need to change any of the default settings for the controller in storyboard - it's all handled in the code below:

//
//  VerticalPagingCollectionViewController.swift
//
//  Created by Don Mag on 10/31/18.
//

import UIKit

private let reuseIdentifier = "Cell"

class VerticalPagingCollectionViewController: UICollectionViewController {

    private var collectionViewFlowLayout: UICollectionViewFlowLayout {
        return collectionViewLayout as! UICollectionViewFlowLayout
    }

    private var colors: [UIColor] = [.red, .green, .blue, .yellow, .orange]

    override func viewDidLoad() {
        super.viewDidLoad()

        // Register cell classes
        self.collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)

        // enable paging
        self.collectionView?.isPagingEnabled = true

        // set section insets and item spacing to Zero
        collectionViewFlowLayout.sectionInset = UIEdgeInsets.zero
        collectionViewFlowLayout.minimumLineSpacing = 0
        collectionViewFlowLayout.minimumInteritemSpacing = 0
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        if let cv = collectionViewLayout.collectionView {
            collectionViewFlowLayout.itemSize = cv.frame.size
        }
    }

    override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if let iPath = collectionView?.indexPathsForVisibleItems.first {
            print("DidEndDecelerating - visible cell is: ", iPath)
            // do what you want here...
        }
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

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

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
        cell.backgroundColor = colors[indexPath.item]
        return cell
    }

}