在UICollectionView中检测页面变化

37

我试图找到这个问题的答案有一段时间了,但并没有找到解决此问题的答案。 我的问题是,我有一个 UICollectionView,滚动方向为 Horizontal,并启用了Paging Enabled。 我想要跟踪用户所在的当前页码,因此我创建了一个int 变量,并希望每次用户向右或向左滑动时将其增加或减少1。我尝试使用 scrollView 的委托。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

但是,当用户向右或向左滑动时,它会被称为页面上UICollectionView列数的次数,并且它不会告诉我用户是转到了下一页还是上一页。


可能是检测UIScrollView页面更改的重复问题。 - shim
完整回答请参见:https://dev59.com/aG435IYBdhLWcg3wrSPN#59057080 - Fattie
8个回答

45

Swift 3 Xcode 8.2

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let x = scrollView.contentOffset.x
        let w = scrollView.bounds.size.width
        let currentPage = Int(ceil(x/w))
        // Do whatever with currentPage.
}

非常感谢您。 :) - iPeter

44

使用:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    CGFloat pageWidth = collectionView.frame.size.width;
    float currentPage = collectionView.contentOffset.x / pageWidth;

    if (0.0f != fmodf(currentPage, 1.0f))
    {
        pageControl.currentPage = currentPage + 1;
    }
    else
    {
        pageControl.currentPage = currentPage;
    }

    NSLog(@"Page Number : %ld", (long)pageControl.currentPage);
}

如果您没有使用任何 pageControl,则 ceil(currentPage) 将是您当前的页面编号。


这个程序完美地实现了需要的功能,只是我无法理解条件语句,所以将其改成了自己的。但是有一个问题,这个方法是在 UICollectionView 的代理方法 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 之后被调用,而我的页面编号变量是在 ScrollView 的代理方法中改变的,因此它不能按照预期工作。有什么解决办法吗? - Ahsan Ebrahim
1
这是正常的行为,当你的CollectionView停止滚动时,这个方法才会被触发..!! - itsji10dra
是的,你说得对。我会尝试找到一些适合我情况的替代方案,但对于这个问题,这是完美的答案。感谢您的帮助。 - Ahsan Ebrahim
很遗憾,它不起作用。你还需要覆盖scrollViewDidEndDragging。https://dev59.com/aG435IYBdhLWcg3wrSPN#59057080 - Fattie
不幸的是,在每种滚动视图更新的情况下,至少在iOS 15中,这并不起作用。例如,即使将animated设置为true,scrollToItem也不会触发此操作。(经常推荐的scrollViewDidEndScrollingAnimation也不起作用,因为动画可能因其他原因被取消)。 - user11638666

12

根据@Shankar BS的答案,我已经在Swift中实现了这个功能。请记住CollectionViewDelegate符合ScrollViewDelegate:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    let pageWidth = scrollView.frame.size.width
    let page = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
    print("page = \(page)")
}

8
您可以按如下方式获取当前页面,索引将从0(总页数-1)
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
 {
    CGFloat pageWidth = scrollView.frame.size.width;
    int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    NSLog(@"Current page -> %d",page);
}

非常感谢.. :) 有没有办法在 UICollectionView 的代理方法 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 之前调用这个方法? - Ahsan Ebrahim

8

SWIFT 5

例如,将此方法放在您的ViewController中,使用扩展方法UICollectionViewDelegate、UICollectionViewDataSource。

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let pageWidth = scrollView.frame.size.width
        let page = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
        print("page = \(page)")
    }

1
在你的答案中添加一些解释或评论可以使它更有帮助。 - nucsit026

4

Swift 2.2

 func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    let x = collectionView.contentOffset.x
    let w = collectionView.bounds.size.width
    let currentPage = Int(ceil(x/w))
    print("Current Page: \(currentPage)")
}

4
您应该在回答中添加一些上下文或评论,而不仅仅是发布代码。 - NickyvV

1

当用户结束拖动时,您可以通过以下方式获取currentPage

已测试并适用于Swift 5.6!

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    let itemWidth = collectionView.frame.width // Get the itemWidth. In my case every cell was the same width as the collectionView itself
    let contentOffset = targetContentOffset.pointee.x

    let targetItem = lround(Double(contentOffset/itemWidth))
    let targetIndex = targetItem % YOUR_ARRAY.count // numberOfItems which shows in the collection view
    print(targetIndex)
}

-1

Xamarin.iOS:

您可以覆盖 UICollectionViewDelegateDecelerationEnded 方法,或者订阅 UICollectionViewDecelerationEnded 事件(在幕后将使用自定义委托)。

public override void DecelerationEnded(UIScrollView scrollView)
{
    var x = scrollView.ContentOffset.X;
    var w = scrollView.Bounds.Size.Width;
    var currentPage = Math.Ceiling(x / w);

    // use currentPage here
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接