自动无限集合查看 - 闪烁

时间:2013-11-25 10:33:34

标签: ios iphone objective-c uicollectionview infinite-scroll

我已经通过几个解决方案检查了UICollectionView中无限滚动的问题,但它们都没有完美运行(123甚至是教程 - 4)。 主要问题在于UICollectionView包含图像。当我滚动到第一个或最后一个项目(使它无限)时,在它们加载之前我可以看到一个非常短的'眨眼'必须被删除。我不知道如何解决它,欢迎任何帮助。

我应该提一下,我正在制作的图库不应该允许任何用户互动,它应该自己滚动(演示文稿可以说)。

我尝试过两种最有趣的方法:

方法1:collectionView中的14个项目,按顺序排列:@ [8,9,@ [0-9],0,1](所以8,9,1,2重复)

// a timer to move everything
_timer = [NSTimer scheduledTimerWithTimeInterval:0.02f target:self selector:@selector(scroll) userInfo:nil repeats:YES];
// timer selector
- (void)scroll {
    self.collectionView.contentOffset = CGPointMake(self.collectionView.contentOffset.x+1, self.collectionView.contentOffset.y);
}

// check if we need to change offset
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"something" forIndexPath:indexPath];
    if ([self scrollProperly]) {
        //        return cell;
    }
}

// method to check & set proper offset (author: D33pN16h7)
- (BOOL)scrollProperly {
    // check if near the end or beginning
    BOOL test = NO;
    CGFloat currentOffsetX = self.collectionView.contentOffset.x;
    CGFloat currentOffSetY = self.collectionView.contentOffset.y;
    CGFloat contentWidth = self.collectionView.contentSize.width;

    if (currentOffsetX < (contentWidth / 6.0f)) {
        self.collectionView.contentOffset = CGPointMake((currentOffsetX + (contentWidth/2)), currentOffSetY);
        test = YES;
    }
    if (currentOffsetX > ((contentWidth * 4)/ 6.0f)) {
        self.collectionView.contentOffset = CGPointMake((currentOffsetX - (contentWidth/2)), currentOffSetY);
        test = YES;
    }
    return test;
}

第二种方法:collectionView中的20个项目,按顺序排列:@ [@ [0-9],@ [0-9]](因此整个数组是重复的)。还有定时器,在以前的方法中也是如此。我们不是在[self scrollProperly]中运行collectionView:cellForItemAtIndexPath:,而是使用:

if (indexPath.row == 2) {
    [collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:([collectionView numberOfItemsInSection:indexPath.section] - 3) inSection:indexPath.section] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
} else if (indexPath.row == ([collectionView numberOfItemsInSection:indexPath.section] - 1)) {
    [collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:indexPath.section] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}

2 个答案:

答案 0 :(得分:1)

好吧,我的最终解决方案是让滚动很长 - 在collectionView:cellForItemAtIndexPath:我正在从我的数据库中读取其大小的模数。在collectionView:numberOfItemsInSection:中,有一个恒定的大小。当我达到恒定大小时,我滚动到第一行。因为我已经制作了恒定大小,所以大量闪烁不会刺激用户,而且滚动实际上是无限的。解决方案并不完美,但我不知道如何解决它。

答案 1 :(得分:1)

我知道这有点晚了但我想出了如何实现一个无限可滚动的UICollectionView;

根据细胞的布局方式,这部分可能会有所不同,但基本上它会分解为这些步骤。

1)修改数据源并在数据阵列的正面和背面复制所需的单元格。

例如,如果您的数据源数组如下所示:

NSArray* array = @[@1, @2, @3, @4, @5];

让我们说它们各自占据视图高度的1/5,你可能希望修改你的数组看起来像这样:

NSArray* array = @[@4, @5, @1, @2, @3, @4, @5, @1, @2, @3];

通过这种方式,你的集合视图基本上是“重复”那些单元格,以给出它继续前进的错觉。

这部分是最难的,因为你修改数据阵列的方式取决于一次在屏幕上适合多少个单元格。如果一次只有一个单元格适合屏幕并且数据数组为@[@1, @2, @3],则可以轻松将其修改为@[@3, @1, @2, @3, @1];(这是this awesome tutorial中的示例。

那我们为什么要这样做呢?这是因为collectionview需要滚动到的东西,即集合视图正面和背面的额外填充。

2)使用键值观察以观察collectionView的contentOffset。

[self.collectionView addObserver:self forKeyPath:@"contentOffset" options:0 context:NULL];

3)检查contentOffset是否已达到优势。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    CGFloat offset = self.collectionView.contentOffset.y;
    if(offset <= 1){
        [self.collectionView setContentOffset:CGPointMake(0, self.collectionView.height-2)];
        [self.collectionView reloadData];
}else if(offset >= self.collectionView.height-1){
        [self.collectionView setContentOffset:CGPointMake(0, 2)];
        [self.collectionView reloadData]; //call to reload the now visible cells, ensure delegate gets called
    }
}

如果contentOffset在顶部边缘的几个像素内,则设置contentOffset,以便集合视图在用户不知道的情况下以静默方式向下滚动页面。当contentOffset到达另一边时,执行相同的操作。

两件非常重要的事情。

1)首次初始化collectionView时,将contentOffset设置为(0,3)。这样,它就会触发KVO方法中的if语句。 2)在KVO方法中设置contentOffset时,还要确保在调用方法时,您设置的点不会触发if语句。

请记住,因为您正在观察contentOffset,所以设置contentOffset会立即触发该方法!只要它没有第二次设置contentOffset,从而导致无限循环的更改通知,你应该没问题。

另请不要忘记将collectionView.bounces设置为YES