objective-c 如何在 iOS 中使 uiscrollview 无限?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19268456/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:05:13  来源:igfitidea点击:

How can I make uiscrollview infinite in iOS?

iphoneobjective-cipaduiscrollviewios7

提问by virantporwal

I want to scroll like that 1 2 3 1 2 3

我想像那样滚动 1 2 3 1 2 3

I have some buttons suppose 10 which i want to show on endless scroll.

我有一些按钮,假设有 10 个,我想在无限滚动中显示它们。

 numbercolors=[[NSMutableArray alloc] init];

 //total count of array is  49 

 numbercolors = [NSMutableArray arrayWithObjects:@"25",@"26",@"27",@"28",@"29",@"31",@"32",@"33",@"34",@"35", @"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23",@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34",@"35", @"0",@"1",@"2",@"3",nil];

  int x=2500;

for (NSInteger index = 0; index < [numbercolors count]; index++)
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

    button.frame = CGRectMake(x ,0,29.0,77.0);

    button.tag = index;

    [button setTitle:[numbercolors objectAtIndex:index] forState:UIControlStateNormal];

    [button addTarget:self action:@selector(didTapButton:) 

    forControlEvents:UIControlEventTouchUpInside];

    [coloringScroll addSubview:button];

    x=x+70+29;
}
 [coloringScroll setContentSize:CGSizeMake(5000+ (29+70)*[numbercolors count], 1)];

 [coloringScroll setContentOffset:CGPointMake(2500+(29+70)*11, 0)];

This is my code for make butttons on scrollview.

这是我在滚动视图上制作按钮的代码。

How can I set in - (void)scrollViewDidEndDecelerating:(UIScrollView *)sender this method for infinite scroll.

如何在 - (void)scrollViewDidEndDecelerating:(UIScrollView *)sender 这个方法中设置无限滚动。

采纳答案by virantporwal

Just need to do set setContentOffset count

只需要设置 setContentOffset 计数

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.contentOffset.x > 2500+(29+70)*4 + ((29+70)*36)) {
        [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x-((29+70)*36),  0)];  
    }
    if (scrollView.contentOffset.x < 2500+(29+70)*4){
       [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x+((29+70)*36), 0)];
    }
}

回答by Guntis Treulands

Main idea is to reposition your scrollview back to some constant value, when it has been scrolled to some value and then auto-reposition your "1" , "2", "3" items correctly.

主要思想是将您的滚动视图重新定位回某个常量值,当它滚动到某个值时,然后正确自动重新定位您的 "1" , "2", "3" 项目。

For example - You would have scrollview with contentwidth 5000. By default You set it to position 2500.

例如 - 您将拥有 contentwidth 5000 的滚动视图。默认情况下,您将其设置为位置 2500。

then You simply check in - (void)scrollViewDidCScroll:(UIScrollView *)scrollview- if scrollview.contentoffset.x > 3500 - then decrease it's position to scrollview.contentoffset.x -=1000;

然后您只需签入- (void)scrollViewDidCScroll:(UIScrollView *)scrollview- 如果 scrollview.contentoffset.x > 3500 - 然后将其位置降低到 scrollview.contentoffset.x -=1000;

and the same about other side. This will result in infinite scrolling.

另一边也一样。这将导致无限滚动。

But content will not follow. So - You would need to implement extra content offset value checking to reorder and reposition correctly "1", "2", "3", items.

但内容不会跟随。所以 - 您需要实施额外的内容偏移值检查以正确重新排序和重新定位“1”、“2”、“3”项。

I usually use 3 elements and then dynamically preload necessary gallery image for them.

我通常使用 3 个元素,然后为它们动态预加载必要的图库图像。

If You don't want to re-invent the "wheel" , check out these solutions:

如果您不想重新发明“轮子”,请查看以下解决方案:

https://www.cocoacontrols.com/controls/dmcircularscrollview

https://www.cocoacontrols.com/controls/dmcircularscrollview

https://www.cocoacontrols.com/controls/infinitescrollview

https://www.cocoacontrols.com/controls/infinitescrollview

https://www.cocoacontrols.com/controls/iainfinitegridview

https://www.cocoacontrols.com/controls/iainfinitegridview

回答by Gerardo Blanco García

You can check out this solution based on Apple StreetScroller iOS sample code:

您可以根据 Apple StreetScroller iOS 示例代码查看此解决方案:

https://github.com/gblancogarcia/GBInfiniteScrollView

https://github.com/gblancogarcia/GBInfiniteScrollView

I hope it helps!

我希望它有帮助!

回答by ninefifteen

I have written an infinite rolling UIscrollView subclass which accomplishes this task. It is based on the Apple StreetScroller sample. You simply provide it with your button titles and whether you want a horizontal or vertical scroll. You can also set many other options. It is posted with documentation and a sample project on my github. Here is the link...

我写了一个无限滚动的 UIscrollView 子类来完成这个任务。它基于 Apple StreetScroller 示例。您只需为它提供按钮标题以及是否需要水平或垂直滚动​​。您还可以设置许多其他选项。它与文档和示例项目一起发布在我的 github 上。链接在这里...

http://github.com/ninefifteen/SSRollingButtonScrollView

http://github.com/ninefifteen/SSRollingButtonScrollView

回答by DragonCherry

This is an old question, but I'm writing this to help whom searching for same solution. Suppose that we wish to infinitely loop through 3 items(cells) - C0, C1, C2, we can generate dummy cells at the left and right side of center cells, the result as follows,

这是一个老问题,但我写这个是为了帮助寻找相同解决方案的人。假设我们希望无限循环遍历3个items(cells)——C0,C1,C2,我们可以在中心单元格的左右两侧生成虚拟单元格,结果如下,

C0 C1 C2 [C0 C1 C2] C0 C1 C2

C0 C1 C2 [C0 C1 C2] C0 C1 C2

Cells in bracket are cells we see through device screen, and if we scroll to left,

括号中的单元格是我们通过设备屏幕看到的单元格,如果我们向左滚动,

C0 [C1 C2 C0] C1 C2 C0 C1 C2

C0 [C1 C2 C0] C1 C2 C0 C1 C2

at this moment, force contentOffset to point right side of given dummy cells,

此时,强制 contentOffset 指向给定虚拟单元格的右侧,

C0 [C1 C2 C0] C1 C2 C0 C1 C2 -> C0 C1 C2 C0 [C1 C2 C0] C1 C2

C0 [C1 C2 C0] C1 C2 C0 C1 C2 -> C0 C1 C2 C0 [C1 C2 C0] C1 C2

Since it's time consuming job to implement this seamlessly, I recommend my solution below.

由于无缝实现这一点非常耗时,因此我推荐下面的解决方案。

https://github.com/DragonCherry/HFSwipeView

https://github.com/DragonCherry/HFSwipeView

If you just wanna check how it works, click link below and "tap to play".

如果您只想查看它是如何工作的,请单击下面的链接并“点按播放”。

https://www.cocoacontrols.com/controls/hfswipeview

https://www.cocoacontrols.com/controls/hfswipeview

回答by niku

For right infinite scroll you can use -

对于正确的无限滚动,您可以使用 -

        let rightOffset = CGPoint.init(x: (scrollView.contentSize.width) - (scrollView.bounds.width), y: 0)
    UIView.animate(withDuration: 3.0,
                   delay: 0.0,
                   options: [.curveLinear, .repeat],
                   animations: { () -> Void in
                    self.scrollView.contentOffset = rightOffset

    }, completion: { (finished: Bool) -> Void in
        self.scrollView.setContentOffset(.init(x: 0, y: self.scrollView.contentOffset.y), animated: false)
    })

回答by Santina

The answers provided here are good but if you're still not satisfied and looking for a different approach here's what I've done.

这里提供的答案很好,但是如果您仍然不满意并正在寻找不同的方法,那么这就是我所做的。

The main idea is to update the number of cells whenever you reach the cell before the last one. Each time you increase the number of items by 1 so it gives the illusion of infinite scrolling. To do that we can utilize scrollViewDidEndDecelerating(_ scrollView: UIScrollView)function to detect when the user has finished scrolling, and then update the number of items in the collection view. Here's a code snippet to achieve that:

主要思想是每当您到达最后一个之前的单元格时更新单元格的数量。每次将项目数增加 1 时,就会产生无限滚动的错觉。为此,我们可以利用scrollViewDidEndDecelerating(_ scrollView: UIScrollView)函数来检测用户何时完成滚动,然后更新集合视图中的项目数。这是实现这一目标的代码片段:

class InfiniteCarouselView: UICollectionView {

    var data: [Any] = []

    private var currentIndex: Int?
    private var currentMaxItemsCount: Int = 0
    // Set up data source and delegate
}

extension InfiniteCarouselView: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        // Set the current maximum to a number above the maximum count by 1
        currentMaxItemsCount = max(((currentIndex ?? 0) + 1), data.count) + 1
        return currentMaxItemsCount

    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        let row = indexPath.row % data.count
        let item = data[row]
        // Setup cell
        return cell
    }
}

extension InfiniteCarouselView: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
    }

    // Detect when the collection view has finished scrolling to increase the number of items in the collection view
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        // Get the current index. Note that the current index calculation will keep changing because the collection view is expanding its content size based on the number of items (currentMaxItemsCount)
        currentIndex = Int(scrollView.contentOffset.x/scrollView.contentSize.width * CGFloat(currentMaxItemsCount))
        // Reload the collection view to get the new number of items
        reloadData()
    }
}

Pros

优点

  • Straightforward implementation
  • No use of Int.max (Which in my own opinion is not a good idea)
  • No use of an arbitrary number (Like 50 or something else)
  • No change or manipulation of the data
  • No manual update of the content offset or any other scroll view attributes
  • 直接实施
  • 不使用 Int.max (在我看来这不是一个好主意)
  • 不使用任意数字(如 50 或其他数字)
  • 不更改或操纵数据
  • 无需手动更新内容偏移量或任何其他滚动视图属性

Cons

缺点

  • Paging should be enabled (Although the logic can be updated to support no paging)
  • Need to maintain a reference for some attributes (current index, current maximum count)
  • Need to reload the collection view on each scroll end (Not a big deal if the visible cells are minimal). This might affect you drastically if you're loading something asynchronously without caching (Which is a bad practice and data should be cached outside the cells)
  • Doesn't work if you want infinite scroll in both directions
  • 应该启用分页(虽然可以更新逻辑以支持无分页)
  • 需要维护一些属性的引用(当前索引,当前最大计数)
  • 需要在每个滚动端重新加载集合视图(如果可见单元格很小,这没什么大不了的)。如果您在没有缓存的情况下异步加载某些内容,这可能会严重影响您(这是一种不好的做法,数据应该缓存在单元格之外)
  • 如果您想在两个方向无限滚动,则不起作用

回答by Luca Davanzo

I've implemented an infinite scroller in swift.
It's inspired by apple StreetScrollerexample

我已经快速实现了一个无限滚动。
它的灵感来自苹果StreetScroller示例

I know is not perfect yet, but I think is a god start point.

我知道现在还不完美,但我认为是一个上帝的起点。

InfiniteVerticalScroller

无限垂直滚动