UICollectionView:像Safari标签或App Storesearch一样进行分页

我想在我的应用程序中实现“卡片”,如Safari标签或App Storesearch。

我将在屏幕的中心显示用户一张牌,并在左侧和右侧显示前一张和下一张牌的一部分。 (请参阅App Storesearch或Safari标签)

我决定使用UICollectionView ,我需要改变页面大小(没有find如何)或实现自己的布局子类(不知道如何)?

请帮忙吗?

下面是我发现得到这个效果的最简单的方法。 它涉及你的collections视图和一个额外的秘密滚动视图。

设置您的collections意见

  • 设置您的collections视图及其所有数据源方法。
  • 构build集合视图; 它应该跨越你想要看到的全部宽度。
  • 设置集合视图的contentInset

     _collectionView.contentInset = UIEdgeInsetsMake(0, (self.view.frame.size.width-pageSize)/2, 0, (self.view.frame.size.width-pageSize)/2); 

这有助于正确地抵消细胞。

设置你的秘密滚动视图

  • 创build一个滚动视图,把它放在任何你喜欢的地方。 如果你喜欢,你可以将其设置为hidden
  • 将滚动视图边界的大小设置为所需的页面大小。
  • 将自己设置为滚动视图的代表。
  • 将其contentSize设置为您的集合视图的预期内容大小。

移动你的手势识别器

  • 将隐藏的滚动视图的手势识别器添加到集合视图,并禁用集合视图的手势识别器:

     [_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer]; _collectionView.panGestureRecognizer.enabled = NO; 

代表

 - (void) scrollViewDidScroll:(UIScrollView *)scrollView { CGPoint contentOffset = scrollView.contentOffset; contentOffset.x = contentOffset.x - _collectionView.contentInset.left; _collectionView.contentOffset = contentOffset; } 

当滚动视图移动时,获取其偏移量并将其设置为集合视图的偏移量。

我在这里发表了博客,所以请查看这个链接的更新: http : //khanlou.com/2013/04/paging-a-overflowing-collection-view/

你可以inheritanceUICollectionViewFlowLayout并覆盖,如下所示:

 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)contentOffset withScrollingVelocity:(CGPoint)velocity { NSArray* layoutAttributesArray = [self layoutAttributesForElementsInRect:self.collectionView.bounds]; if(layoutAttributesArray.count == 0) return contentOffset; UICollectionViewLayoutAttributes* candidate = layoutAttributesArray.firstObject; for (UICollectionViewLayoutAttributes* layoutAttributes in layoutAttributesArray) { if (layoutAttributes.representedElementCategory != UICollectionElementCategoryCell) continue; if((velocity.x > 0.0 && layoutAttributes.center.x > candidate.center.x) || (velocity.x <= 0.0 && layoutAttributes.center.x < candidate.center.x)) candidate = layoutAttributes; } return CGPointMake(candidate.center.x - self.collectionView.bounds.size.width * 0.5f, contentOffset.y); } 

这将获得下一个或上一个单元格取决于速度…但它不会捕捉当前单元格。

@Mike M的 Swift 答案

 class CenteringFlowLayout: UICollectionViewFlowLayout { override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { guard let collectionView = collectionView, let layoutAttributesArray = layoutAttributesForElementsInRect(collectionView.bounds), var candidate = layoutAttributesArray.first else { return proposedContentOffset } layoutAttributesArray.filter({$0.representedElementCategory == .Cell }).forEach { layoutAttributes in if (velocity.x > 0 && layoutAttributes.center.x > candidate.center.x) || (velocity.x <= 0 && layoutAttributes.center.x < candidate.center.x) { candidate = layoutAttributes } } return CGPoint(x: candidate.center.x - collectionView.bounds.width / 2, y: proposedContentOffset.y) } } 

对Soroush的回答稍作编辑,这对我来说是个诀窍。 我唯一的编辑,而不是禁用手势:

 [_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer]; _collectionView.panGestureRecognizer.enabled = NO; 

我禁用滚动collectionview:

 _collectionView.scrollEnabled = NO; 

由于禁用该手势,所以也禁用了该秘密的滚动视图手势。

我会添加另一个解决scheme。 捕捉到的地方并不完美(不如启用分页function时效果不错,但效果不错)。

我尝试过实施Soroush的解决scheme,但是这对我不起作用。

由于UICollectionViewUIScrollView的子类,它将响应一个重要的UIScrollViewDelegate方法,它是:

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset 

targetContentOffset (一个inout指针 )让你重新定义一个集合视图的停靠点(在这种情况下,如果你水平滑动的话)。

关于下面几个variables的简要说明:

  • self.cellWidth – 这是你的集合视图单元格的宽度(你可以在那里硬编码,如果你想)

  • self.minimumLineSpacing – 这是您在单元格之间设置的最小行距

  • self.scrollingObjects是包含在集合视图中的对象数组(我主要需要这个计数,知道何时停止滚动)

所以,这个想法是在集合视图的委托中实现这个方法,就像这样:

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { if (self.currentIndex == 0 && velocity.x < 0) { // we have reached the first user and we're trying to go back return; } if (self.currentIndex == (self.scrollingObjects.count - 1) && velocity.x > 0) { // we have reached the last user and we're trying to go forward return; } if (velocity.x < 0) { // swiping from left to right (going left; going back) self.currentIndex--; } else { // swiping from right to left (going right; going forward) self.currentIndex++; } float xPositionToStop = 0; if (self.currentIndex == 0) { // first row xPositionToStop = 0; } else { // one of the next ones xPositionToStop = self.currentIndex * self.cellWidth + (self.currentIndex + 1) * self.minimumLineSpacing - ((scrollView.bounds.size.width - 2*self.minimumLineSpacing - self.cellWidth)/2); } targetContentOffset->x = xPositionToStop; NSLog(@"Point of stopping: %@", NSStringFromCGPoint(*targetContentOffset)); } 

期待任何反馈,您可能会有更好的捕捉。 我也会继续寻找更好的解决scheme…

以前是相当复杂的,UICollectionView是UIScrollView的子类,所以只需要这样做:

 [self.collectionView setPagingEnabled:YES]; 

你们都准备好了

看到这个详细的教程 。