带有“循环”滚动的UIScrollView

16

我正在尝试在我的UIScrollView中实现“循环”滚动,但尝试未果。

我想要做的是: 如果UIScrollView到达末尾,它应该移动到开头 如果UIScrollView在开头并且向后移动,它应该移动到末尾

在我的情况下,附加滚动视图不是好的方法(其他方法应该获取“页面ID”)

你有什么想法吗?


使用滚动视图属性。我已经理解你所问的内容。 - vishiphone
现在我已经搜索到了我在项目中使用的内容,我认为你想要左右两侧各一张图片和背面也有一张图片,并且它像一个水平圆环一样旋转。 - vishiphone
4个回答

42

我已经实现了这个方法,但是它要求分页启用。假设你有五个元素 A,B,C,D和E。当你设置你的视图时,你把最后一个元素添加到开头,把第一个元素添加到结尾,并调整内容偏移量以查看第一个元素,像这样 E,[A],B,C,D,E,A。在UIScrollViewDelegate中,检查用户是否到达任何一端,并将偏移值无动画地移动到另一端。

想象一下[ ]表示正在显示的视图:

E,A,B,C,[D],E,A

用户向右滑动

E,A,B,C,D,[E],A

用户向右滑动

E,A,B,C,D,E,[A]

然后,自动将内容偏移量设置为第二个元素

E,[A],B,C,D,E,A

通过这种方式,用户可以向两个方向滑动,创造出无限滚动的错觉。

E,A,[B],C,D,E,A


更新

我已经上传了这个算法的一个完整实现。这是一个非常复杂的类,因为它还具有单击选择、无限循环滚动和单元格重用。您可以直接使用代码,修改它或提取您需要的代码。最有趣的代码在类TCHorizontalSelectorView中。

文件链接

尽情享受吧!


更新2

UICollectionView 现在是推荐的方法,并且可以用来获得完全相同的行为。 这篇教程详细描述了如何实现这一点。


我的滚动视图启用了分页功能。 - werbary
谢谢,这是一个很棒的解决方案。 - werbary
我应该使用哪个事件从最后一个元素到第二个元素? - kbtz
@sMember,你可以在scrollViewDidEndDecelerating代理方法中进行切换。我已经添加了一个完整的示例,你可以使用它或者查看它是如何实现的。 - redent84
很好的解决方案,讲解得非常清楚 :) +1 - iAkshay

4

苹果公司有一个Street Scroller演示,看起来正是你所需要的。

此外,还有一个视频来自2011 WWDC展示他们的演示。 ;) 他们在视频中首先介绍了无限滚动。


1
+1 很好,但它不能与分页一起使用,至少不能直接使用。我尝试启用分页,但框架似乎比显示器大。也许需要进行一些调整。 - Kai Huppmann
@Kai 这并不是为了分页而设计的,我也不确定 OP 实际上是否想要分页。我知道它已启用,但无限滚动!=分页。根据他的问题,它更像是一个横向滚动的游戏,而不是一个无限覆盖流。如果实际上是分页,你可以使用苹果的演示来加载 UIPageControl 并简单修改代码,在你超出实际索引区域时使用余数数学。 - mbm29414

0

尝试使用以下代码...

示例代码...

- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender 
    {

        if (scrollView.contentOffset.x == 0) {
            // user is scrolling to the left from image 1 to image n(last image).
            // reposition offset to show image 10 that is on the right in the scroll view
            [scrollView scrollRectToVisible:CGRectMake(4000,0,320,480) animated:NO];// you can define your `contensize` for scrollview
        }
        else if (scrollView.contentOffset.x == 4320) {
            // user is scrolling to the right from image n(last image) to image 1.
            // reposition offset to show image 1 that is on the left in the scroll view
            [scrollView scrollRectToVisible:CGRectMake(320,0,320,480) animated:NO];
        }
    }

希望这能对你有所帮助...


以上代码应该可以工作,但我不知道为什么它没有工作。然后访问此网址。它还包含示例代码>>> http://mobiledevelopertips.com/user-interface/creating-circular-and-infinite-uiscrollviews.html ... - Nitin
1
这段代码具体是如何解决提问者的问题的? - Peter Hosey

0

参考 @redent84,找到代码逻辑。

覆盖重写 `func viewWillAppear(_ animated: Bool)`

{
    super.viewWillAppear(animated)

    scrollView.contentSize = CGSize(width: scrollView.frame.width * CGFloat(imagesArray.count), height: scrollView.frame.height)

    scrollView.isPagingEnabled = true

    //        imagesArray.insert(imagesArray.last as? UIImage, at: 0)
    //        imagesArray.insert(imagesArray.first as? UIImage, at: imagesArray.count - 1)


    var testArr = ["A", "B", "C", "D"]

    let firstItem = testArr.first
    let lastItem = testArr.last

    testArr.insert(lastItem as! String, at: 0)
    testArr.append(firstItem as! String)
    print(testArr)


    for i in 0..<imagesArray.count{
        let imageview = UIImageView()
        imageview.image = imagesArray[i]
        imageview.contentMode = .scaleAspectFit
        imageview.clipsToBounds = true
        let xPosition = self.scrollView.frame.width * CGFloat(i)
        imageview.frame = CGRect(x: xPosition, y: 0, width: self.scrollView.frame.width, height: self.scrollView.frame.height)
        print(imageview)
        scrollView.addSubview(imageview)

        print("Imageview frames of i \(i) is \(imageview.frame)")
    }

    newStartScrolling()
}

func newStartScrolling()
{
    ViewController.i += 1

    let x = CGFloat(ViewController.i) * scrollView.frame.size.width
    scrollView.setContentOffset(CGPoint(x: x, y: 0), animated: true)

    print("X is \(x) and i is \(ViewController.i)")

    if ViewController.i == imagesArray.count - 1 {
        ViewController.i = 0
        let x = CGFloat(ViewController.i) * scrollView.frame.size.width
        //scrollView.setContentOffset(CGPoint(x: x, y: 0), animated: false)
        print("X (rotate) is \(x) and i is \(ViewController.i)")
        scrollView.contentOffset.x = x
        self.newStartScrolling()

    }

}

func backScrolling()  {
    ViewController.i -= 1

    let x = CGFloat(ViewController.i) * scrollView.frame.size.width
    scrollView.setContentOffset(CGPoint(x: x, y: 0), animated: true)
    print("X is \(x) and i is \(ViewController.i)")
    if ViewController.i <= 0 {
        ViewController.i = imagesArray.count - 1
        let x = CGFloat(ViewController.i) * scrollView.frame.size.width
         scrollView.setContentOffset(CGPoint(x: x, y: 0), animated: false)
        print("X (rotate) is \(x) and i is \(ViewController.i)")

        self.backScrolling()
        //scrollView.contentOffset.x = x
        return
    }

}

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