检测距离集合视图中心最近的集合视图单元
Detecting closest collectionviewcell to the center of the collectionview
怀疑我在下面做了一些根本性的错误...我有一个水平的集合视图,拖动后我想将最近的单元格对齐到中心。但是我的结果是不可预测的...我在这里做错了什么?
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)
}
试试这个:
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)
原来我的原始代码缺少对 collecitonview 内容偏移的说明。此外,我已将居中移动到 scrollViewDidEndDecelerating 回调中。我已经修改了原始代码并将其包含在下面。
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)
}
更新版本 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)
- 停止拖动时,只需选择中心并用它来选择索引路径
swift 4.2
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let indexPath = photoCollectionView.indexPathForItem(at: photoCollectionView.center)
photoCollectionView.scrollToItemAtIndexPath(indexPath!, atScrollPosition: .centeredHorizontally, animated: true)
}
None 的解决方案可靠地为我工作,所以我写了这个并且它在 100% 的时间内工作。很简单的。即使是内置的 indexPathForItemAtPoint 也不能 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
}
}
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:需要确保我们 将点从超级视图坐标 space 转换为 collectionView 的 space
2:使用collectionView的本地space点找到indexPath
3: Return indexPath 的单元格
public func closestIndexPathToCenter() -> IndexPath? {
guard let cv = collectionView else { return nil }
let visibleCenterPositionOfScrollView = Float(cv.contentOffset.x + (cv.bounds.size.width / 2))
var closestCellIndex = -1
var closestDistance: Float = .greatestFiniteMagnitude
for i in 0..<cv.visibleCells.count {
let cell = cv.visibleCells[i]
let cellWidth = cell.bounds.size.width
let cellCenter = Float(cell.frame.origin.x + cellWidth / 2)
// Now calculate closest cell
let distance: Float = fabsf(visibleCenterPositionOfScrollView - cellCenter)
if distance < closestDistance {
closestDistance = distance
closestCellIndex = cv.indexPath(for: cell)!.row
}
}
if closestCellIndex != -1 {
return IndexPath(row: closestCellIndex, section: 0)
}else {
return nil
}
}
怀疑我在下面做了一些根本性的错误...我有一个水平的集合视图,拖动后我想将最近的单元格对齐到中心。但是我的结果是不可预测的...我在这里做错了什么?
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)
}
试试这个:
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)
原来我的原始代码缺少对 collecitonview 内容偏移的说明。此外,我已将居中移动到 scrollViewDidEndDecelerating 回调中。我已经修改了原始代码并将其包含在下面。
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)
}
更新版本 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)
- 停止拖动时,只需选择中心并用它来选择索引路径
swift 4.2
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let indexPath = photoCollectionView.indexPathForItem(at: photoCollectionView.center)
photoCollectionView.scrollToItemAtIndexPath(indexPath!, atScrollPosition: .centeredHorizontally, animated: true)
}
None 的解决方案可靠地为我工作,所以我写了这个并且它在 100% 的时间内工作。很简单的。即使是内置的 indexPathForItemAtPoint 也不能 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
}
}
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:需要确保我们 将点从超级视图坐标 space 转换为 collectionView 的 space
2:使用collectionView的本地space点找到indexPath
3: Return indexPath 的单元格
public func closestIndexPathToCenter() -> IndexPath? {
guard let cv = collectionView else { return nil }
let visibleCenterPositionOfScrollView = Float(cv.contentOffset.x + (cv.bounds.size.width / 2))
var closestCellIndex = -1
var closestDistance: Float = .greatestFiniteMagnitude
for i in 0..<cv.visibleCells.count {
let cell = cv.visibleCells[i]
let cellWidth = cell.bounds.size.width
let cellCenter = Float(cell.frame.origin.x + cellWidth / 2)
// Now calculate closest cell
let distance: Float = fabsf(visibleCenterPositionOfScrollView - cellCenter)
if distance < closestDistance {
closestDistance = distance
closestCellIndex = cv.indexPath(for: cell)!.row
}
}
if closestCellIndex != -1 {
return IndexPath(row: closestCellIndex, section: 0)
}else {
return nil
}
}