问题
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