UICollectionView与CustomFlowLayout如何限制每滚动只有一个页面滚动?

我在我的iOS应用程序中实现了customFlowLayout 。 我已经通过子类化UICollectionViewFlowLayout子类化了targetContentOffsetForProposedContentOffset:withScrollingVelocity UICollectionViewFlowLayout 。 现在我的问题是当用户滚动collectionview它必须滚动到只有下一个索引。 现在它随机滚动。
所以任何人都有任何想法,我怎样才能使滚动限制只有一个项目每卷。
以下是我的代码。

 #pragma mark - UICollectionViewLayout (UISubclassingHooks) - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { CGSize collectionViewSize = self.collectionView.bounds.size; CGFloat proposedContentOffsetCenterX = proposedContentOffset.x + collectionViewSize.width / 2; CGRect proposedRect = CGRectMake(proposedContentOffset.x, 0, collectionViewSize.width, collectionViewSize.height); UICollectionViewLayoutAttributes *candidateAttributes; for (UICollectionViewLayoutAttributes *attributes in [self layoutAttributesForElementsInRect:proposedRect]) { if (attributes.representedElementCategory != UICollectionElementCategoryCell) continue; if (!candidateAttributes) { candidateAttributes = attributes; continue; } if (fabs(attributes.center.x - proposedContentOffsetCenterX) < fabs(candidateAttributes.center.x - proposedContentOffsetCenterX)) { candidateAttributes = attributes; } } proposedContentOffset.x = candidateAttributes.center.x - self.collectionView.bounds.size.width / 2; CGFloat offset = proposedContentOffset.x - self.collectionView.contentOffset.x; if ((velocity.x < 0 && offset > 0) || (velocity.x > 0 && offset < 0)) { CGFloat pageWidth = self.itemSize.width + self.minimumLineSpacing; proposedContentOffset.x += velocity.x > 0 ? pageWidth : -pageWidth; } return proposedContentOffset; } - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES; } - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { if (!self.scaleItems) return [super layoutAttributesForElementsInRect:rect]; NSArray *attributesArray = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES]; CGRect visibleRect = (CGRect){self.collectionView.contentOffset, self.collectionView.bounds.size}; CGFloat visibleCenterX = CGRectGetMidX(visibleRect); [attributesArray enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *attributes, NSUInteger idx, BOOL *stop) { CGFloat distanceFromCenter = visibleCenterX - attributes.center.x; CGFloat absDistanceFromCenter = MIN(ABS(distanceFromCenter), self.scalingOffset); CGFloat scale = absDistanceFromCenter * (self.minimumScaleFactor - 1) / self.scalingOffset + 1; attributes.transform3D = CATransform3DScale(CATransform3DIdentity, scale, scale, 1); }]; return attributesArray; } 

您的代码看起来应该根据用户请求很好地滚动。 即如果他们快速滚动,它将跳过一些项目,很好地落在后面的项目,如果他们慢慢滚动,将进行到下一个或返回到前一个项目很好地根据滚动距离。 但是,这不是你说的你想要的。

当用户试图快速滚动时,您想要的内容可能不太好

无论如何,要得到你想要的,你基本上只想使用proposedContentOffset来确定滚动方向(是大于还是小于当前的内容偏移量)。

现在,一旦你有了,你可以得到在下一页或上一页的项目的布局属性(而不是当前的代码,可能获得多个页面的属性)。 这是当前偏移+或 – 视图宽度。

其余的代码保持不变。 忽略滚动方向,就像这样:

 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { CGSize collectionViewSize = self.collectionView.bounds.size; CGFloat width = collectionViewSize.width; CGFloat halfWidth = width * 0.5; CGFloat direction = (proposedContentOffset.x > self.collectionView.contentOffset.x ? 1 : 0); CGFloat pageOffsetX = 250.0 * floor(self.collectionView.contentOffset.x / 250.0); CGFloat proposedContentOffsetCenterX = pageOffsetX + (width * direction); CGRect proposedRect = CGRectMake(proposedContentOffsetCenterX, 0, collectionViewSize.width, collectionViewSize.height); UICollectionViewLayoutAttributes *candidateAttributes; for (UICollectionViewLayoutAttributes *attributes in [self layoutAttributesForElementsInRect:proposedRect]) { if (attributes.representedElementCategory != UICollectionElementCategoryCell) continue; candidateAttributes = attributes; break; } proposedContentOffset.x = candidateAttributes.center.x - halfWidth; // CGFloat offset = proposedContentOffset.x - self.collectionView.contentOffset.x; // // if ((velocity.x < 0 && offset > 0) || (velocity.x > 0 && offset < 0)) { // CGFloat pageWidth = self.itemSize.width + self.minimumLineSpacing; // proposedContentOffset.x += velocity.x > 0 ? pageWidth : -pageWidth; // } return proposedContentOffset; } 

我已经注意到底部的部分,因为它不应该是最初版本所必需的。 先用一个简单的版本进行testing,然后详细说明是否需要在边缘情况下进行更多的控制。