动画UICollectionView contentOffset不显示不可见的单元格

rav*_*vun 22 animation ios contentoffset uicollectionview

我正在研究一些类似自动收报机的功能,并且正在使用UICollectionView.它最初是一个scrollView,但我们认为collectionView可以更容易地添加/删除单元格.

我使用以下内容为collectionView设置动画:

- (void)beginAnimation {
    [UIView animateWithDuration:((self.collectionView.collectionViewLayout.collectionViewContentSize.width - self.collectionView.contentOffset.x) / 75) delay:0 options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionRepeat | UIViewAnimationOptionBeginFromCurrentState) animations:^{
        self.collectionView.contentOffset = CGPointMake(self.collectionView.collectionViewLayout.collectionViewContentSize.width, 0);
    } completion:nil];
}
Run Code Online (Sandbox Code Playgroud)

这适用于滚动视图,动画发生在集合视图中.但是,实际上只渲染动画结尾处可见的单元格.cellForItemAtIndexPath调用contentOffset不会导致调用.当contentOffset更改时,如何让单元格呈现?

编辑:更多参考(不确定它是否有很多帮助):

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    TickerElementCell *cell = (TickerElementCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"TickerElementCell" forIndexPath:indexPath];
    cell.ticker = [self.fetchedResultsController objectAtIndexPath:indexPath];
    return cell;
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

    // ...

    [self loadTicker];
}

- (void)loadTicker {

    // ...

    if (self.animating) {
        [self updateAnimation];
    }
    else {
        [self beginAnimation];
    }
}

- (void)beginAnimation {

    if (self.animating) {
        [self endAnimation];
    }

    if ([self.tickerElements count] && !self.animating && !self.paused) {
        self.animating = YES;
        self.collectionView.contentOffset = CGPointMake(1, 0);
        [UIView animateWithDuration:((self.collectionView.collectionViewLayout.collectionViewContentSize.width - self.collectionView.contentOffset.x) / 75) delay:0 options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionBeginFromCurrentState) animations:^{
            self.collectionView.contentOffset = CGPointMake(self.collectionView.collectionViewLayout.collectionViewContentSize.width, 0);
        } completion:nil];
    }
}
Run Code Online (Sandbox Code Playgroud)

Ami*_*itP 39

你应该简单地[self.view layoutIfNeeded];在动画块内添加,如下所示:

[UIView animateWithDuration:((self.collectionView.collectionViewLayout.collectionViewContentSize.width - self.collectionView.contentOffset.x) / 75) delay:0 options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionBeginFromCurrentState) animations:^{
            self.collectionView.contentOffset = CGPointMake(self.collectionView.collectionViewLayout.collectionViewContentSize.width, 0);
            [self.view layoutIfNeeded];
        } completion:nil];
Run Code Online (Sandbox Code Playgroud)

  • 这对我不起作用.细胞仍然消失. (8认同)
  • 这很好,谢谢你的回答.我将补充说,我必须在`UIView.performWithoutAnimations`块中包装`layoutIfNeeded`,以避免动画新近可见单元格的大小.将它立即包装在`animateWithDuration`中感觉很奇怪,但效果很好. (5认同)
  • 为什么这甚至有效?但它太棒了! (4认同)

dev*_*vid 7

您可以尝试使用CADisplayLink自行驱动动画.设置起来并不难,因为无论如何都要使用线性动画曲线.这是一个可能适合您的基本实现:

@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic, assign) CFTimeInterval lastTimerTick;
@property (nonatomic, assign) CGFloat animationPointsPerSecond;
@property (nonatomic, assign) CGPoint finalContentOffset;

-(void)beginAnimation {
    self.lastTimerTick = 0;
    self.animationPointsPerSecond = 50;
    self.finalContentOffset = CGPointMake(..., ...);
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick:)];
    [self.displayLink setFrameInterval:1];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

-(void)endAnimation {
    [self.displayLink invalidate];
    self.displayLink = nil;
}

-(void)displayLinkTick {
    if (self.lastTimerTick = 0) {
        self.lastTimerTick = self.displayLink.timestamp;
        return;
    }
    CFTimeInterval currentTimestamp = self.displayLink.timestamp;
    CGPoint newContentOffset = self.collectionView.contentOffset;
    newContentOffset.x += self.animationPointsPerSecond * (currentTimestamp - self.lastTimerTick)
    self.collectionView.contentOffset = newContentOffset;

    self.lastTimerTick = currentTimestamp;

    if (newContentOffset.x >= self.finalContentOffset.x)
        [self endAnimation];
}
Run Code Online (Sandbox Code Playgroud)

  • 现在,@ AmitP的回答似乎更合适 (3认同)