无论滚动速度如何,如何在每次滑动时将集合视图项捕捉到一个

Posted

技术标签:

【中文标题】无论滚动速度如何,如何在每次滑动时将集合视图项捕捉到一个【英文标题】:how to snap collection view items to one per swipe regardless of scrolling velocity 【发布时间】:2013-12-05 22:29:07 【问题描述】:

我在 UICollectionViewFlowLayout 的子类中使用 Apple 演示中的代码:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity

    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter = proposedContentOffset.x + self.collectionView.bounds.size.width / 2.;
    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0., self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

    UICollectionViewLayoutAttributes *targetAttributes = nil;
    NSArray *attributes = [super layoutAttributesForElementsInRect:targetRect];
    for (UICollectionViewLayoutAttributes *a in attributes) 
        CGFloat itemHorizontalCenter = a.center.x;
        if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offsetAdjustment)) 
            offsetAdjustment = itemHorizontalCenter - horizontalCenter;
            targetAttributes = a;
        
    

    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);

这在某种意义上是有效的,每当我滑动/平移并释放时,一个项目就会卡入到位。但建议的内容偏移量与滑动速度成正比。我想要做的是,无论我滑动多快/多慢,集合视图只会捕捉到当前居中的项目之前或之后的下一个项目。

我试过这样做:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity

    NSInteger currentPage = (int)(self.collectionView.contentOffset.x / self.collectionView.bounds.size.width);
    if (proposedContentOffset.x > self.collectionView.contentOffset.x) 
        currentPage = (MIN(currentPage + 1, ((int)(self.collectionView.contentSize.width / self.collectionView.bounds.size.width)) - 1));
    

    proposedContentOffset.x = self.collectionView.bounds.size.width * currentPage;

    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter = proposedContentOffset.x + self.collectionView.bounds.size.width / 2.;
    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0., self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

    UICollectionViewLayoutAttributes *targetAttributes = nil;
    NSArray *attributes = [super layoutAttributesForElementsInRect:targetRect];
    for (UICollectionViewLayoutAttributes *a in attributes) 
        CGFloat itemHorizontalCenter = a.center.x;
        if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offsetAdjustment)) 
            offsetAdjustment = itemHorizontalCenter - horizontalCenter;
            targetAttributes = a;
        
    

    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);

但这并不完全正确。有时它会跳过一个项目并在此之后捕捉到下一个项目(也就是说,它不会捕捉到紧挨我开始滚动的项目旁边的项目,而是紧邻下一个项目的项目)。

有什么想法吗?

【问题讨论】:

【参考方案1】:

好的,所以我想出了如何通过使所有内容都与当前的 contentOffset 相关来使其工作:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity

    if (proposedContentOffset.x > self.collectionView.contentOffset.x) 
        proposedContentOffset.x = self.collectionView.contentOffset.x + self.collectionView.bounds.size.width / 2.;
    
    else if (proposedContentOffset.x < self.collectionView.contentOffset.x) 
        proposedContentOffset.x = self.collectionView.contentOffset.x - self.collectionView.bounds.size.width / 2.;
    

    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter = proposedContentOffset.x + self.collectionView.bounds.size.width / 2.;
    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0., self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

    NSArray *attributes = [super layoutAttributesForElementsInRect:targetRect];
    for (UICollectionViewLayoutAttributes *a in attributes) 
        CGFloat itemHorizontalCenter = a.center.x;
        if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offsetAdjustment)) 
            offsetAdjustment = itemHorizontalCenter - horizontalCenter;
        
    

    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);

【讨论】:

您的代码运行良好。我们可以让它一次只滚动一个页面吗?目前,就我而言,如果我滚动得太快,它将跳过多个页面。这是我的question。

以上是关于无论滚动速度如何,如何在每次滑动时将集合视图项捕捉到一个的主要内容,如果未能解决你的问题,请参考以下文章

如何使用滚动视图使隐藏的按钮菜单出现/消失?

Swift UIScrollView 在没有 pagingEnabled 的情况下捕捉到子视图宽度

如何在 iOS 设备上的滑动手势期间“捕捉”子视图?

如何通过手指获取 UIScrollView 分页?

如何在滚动时将单元格的内容保留在屏幕上,直到单元格用完可用空间?

启用分页时将水平可滚动集合视图的单元格居中并使其他单元格部分可见