Detecting closest collectionviewcell to the center of the collectionview

最后都变了- 提交于 2020-12-29 06:18:29

问题


Suspect I am doing something fundamentally wrong below... I have a horizontal collectionview and after dragging I want to snap the closest cell to the center. But my results are unpredictable... what am I doing wrong here?

    func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    // Find collectionview cell nearest to the center of collectionView
    // Arbitrarily start with the last cell (as a default)
    var closestCell : UICollectionViewCell = collectionView.visibleCells()[0];
    for cell in collectionView!.visibleCells() as [UICollectionViewCell] {
        let closestCellDelta = abs(closestCell.center.x - collectionView.bounds.size.width/2.0)
        let cellDelta = abs(cell.center.x - collectionView.bounds.size.width/2.0)
        if (cellDelta < closestCellDelta){
            closestCell = cell
        }
    }
    let indexPath = collectionView.indexPathForCell(closestCell)
    collectionView.scrollToItemAtIndexPath(indexPath!, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)
}

回答1:


Turns out my original code was missing accounting for the collecitonview content offset. In addition, I've moved the centering into the scrollViewDidEndDecelerating callback. I've modified the original code and included it below.

    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    // Find collectionview cell nearest to the center of collectionView
    // Arbitrarily start with the last cell (as a default)
    var closestCell : UICollectionViewCell = collectionView.visibleCells()[0];
    for cell in collectionView!.visibleCells() as [UICollectionViewCell] {
        let closestCellDelta = abs(closestCell.center.x - collectionView.bounds.size.width/2.0 - collectionView.contentOffset.x)
        let cellDelta = abs(cell.center.x - collectionView.bounds.size.width/2.0 - collectionView.contentOffset.x)
        if (cellDelta < closestCellDelta){
            closestCell = cell
        }
    }
    let indexPath = collectionView.indexPathForCell(closestCell)
    collectionView.scrollToItemAtIndexPath(indexPath!, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)
}



回答2:


Try this:

NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:self.collectionView.center];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];

SWIFT:

let indexPath = self.collectionView.indexPathForItemAtPoint(self.collectionView.center)
self.collectionView.scrollToItemAtIndexPath(indexPath!, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)



回答3:


None of the solutions reliably worked for me, so I wrote this and it works 100% of the time. Very simple. Even the built in indexPathForItemAtPoint was not working 100%.

extension UICollectionView {
    
    var centerMostCell:UICollectionViewCell? {
        guard let superview = superview else { return nil }
        let centerInWindow = superview.convert(center, to: nil)
        guard visibleCells.count > 0 else { return nil }
        var closestCell:UICollectionViewCell?
        for cell in visibleCells {
            guard let sv = cell.superview else { continue }
            let cellFrameInWindow = sv.convert(cell.frame, to: nil)
            if cellFrameInWindow.contains(centerInWindow) {
                closestCell = cell
                break
            }
        }
        return closestCell
    }
    
}



回答4:


Updated version for Swift 4

var closestCell = collectionView.visibleCells[0]
for cell in collectionView.visibleCells {
    let closestCellDelta = abs(closestCell.center.x - collectionView.bounds.size.width/2.0 - collectionView.contentOffset.x)
    let cellDelta = abs(cell.center.x - collectionView.bounds.size.width/2.0 - collectionView.contentOffset.x)
    if (cellDelta < closestCellDelta){
        closestCell = cell
    }
}

let indexPath = collectionView.indexPath(for: closestCell)
collectionView.scrollToItem(at: indexPath!, at: .centeredHorizontally, animated: true)



回答5:


  • When stop dragging, just pick the center and use it to choose the indexpath

swift 4.2

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    let indexPath = photoCollectionView.indexPathForItem(at: photoCollectionView.center)
    photoCollectionView.scrollToItemAtIndexPath(indexPath!, atScrollPosition: .centeredHorizontally, animated: true)
}



回答6:


var centerUICollectionViewCell: UICollectionViewCell? {
  get {
    // 1 
    guard let center = collectionView.superview?.convert(collectionView.center, to: collectionView) else { return nil }

    // 2  
    guard let centerIndexPath = collectionView.indexPathForItem(at: center) else { return nil }

    // 3
    return collectionView.cellForItem(at: centerIndexPath)
  }
}

1: Need to make sure we are converting the point from superview coordinate space to collectionView's space

2: Use the collectionView's local space point to find the indexPath

3: Return the cell for indexPath



来源:https://stackoverflow.com/questions/32878297/detecting-closest-collectionviewcell-to-the-center-of-the-collectionview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!