【问题标题】:Animation Duration for UICollectionView selectItemAtIndexPath:animated:scrollPosition:UICollectionView 的动画持续时间 selectItemAtIndexPath:animated:scrollPosition:
【发布时间】:2013-05-16 20:58:11
【问题描述】:

我已尝试设置持续时间(使用我会尝试的常规方法)以设置 UICollectionView 的 selectItemAtIndexPath:animated:scrollPosition: 方法(或 scrollToItemAtIndexPath:atScrollPosition:animated: 方法)的动画持续时间。我尝试过[UIView setAnimationDuration],并尝试将其包装在CATransaction 中。到目前为止,我在更​​改动画持续时间方面一直没有成功(尽管我承认我可能在这个逻辑上犯了一个错误)。

想法?

更新:

我在这里尝试了很多方法。最接近的解决方案是执行我们通常为 UIScrollView 动画所做的事情(通过将 animated: 参数设置为 NO 并将其包装在 UIView 动画块中)。这对于滚动视图非常有效。但是,由于某种原因,这与UICollectionView 创建过程有关。

我在下面包含了一个使用两种方法的示例。每种方法都假设您有 4 个部分,每个部分包含 4 个项目。此外,动画假定您从 0,0 移动到 3,3。

使用默认动画

这里的部分问题似乎与UICollectionView 有关。如果您采用以下方法(使用默认动画选项) - 一切正常:

[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
                                atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                        animated:YES];

执行此操作时,将创建当前可见单元格和目标单元格之间的每个单元格。我已经包括登录collectionView:cellForItemAtIndexPath: 方法:

2013-05-18 09:33:24.366 DEF-CV-Testing[75463:c07] Transition
Cell Created for Index Path: <NSIndexPath 0x8913f40> 2 indexes [0, 1]
Cell Created for Index Path: <NSIndexPath 0x75112e0> 2 indexes [0, 2]
Cell Created for Index Path: <NSIndexPath 0xfe1a6c0> 2 indexes [0, 3]
Cell Created for Index Path: <NSIndexPath 0x89159e0> 2 indexes [1, 0]
Cell Created for Index Path: <NSIndexPath 0x8a10e70> 2 indexes [1, 1]
Cell Created for Index Path: <NSIndexPath 0x7510d90> 2 indexes [1, 2]
Cell Created for Index Path: <NSIndexPath 0x75112a0> 2 indexes [1, 3]
Cell Created for Index Path: <NSIndexPath 0x8915a00> 2 indexes [2, 0]
Cell Created for Index Path: <NSIndexPath 0x75111c0> 2 indexes [2, 1]
Cell Created for Index Path: <NSIndexPath 0xfe17f30> 2 indexes [2, 2]
Cell Created for Index Path: <NSIndexPath 0xfe190c0> 2 indexes [2, 3]
Cell Created for Index Path: <NSIndexPath 0xfe16920> 2 indexes [3, 0]
Cell Created for Index Path: <NSIndexPath 0x75112a0> 2 indexes [3, 1]
Cell Created for Index Path: <NSIndexPath 0xfe1a4f0> 2 indexes [3, 2]
Cell Created for Index Path: <NSIndexPath 0x75142d0> 2 indexes [3, 3]

使用自定义动画

scrollToItemAtIndexPath: 方法包装在UIView 动画块中时,无法正确创建项目。在此处查看代码示例:

[UIView animateWithDuration:5.0 delay:0.0 options:0 animations:^{
    [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
                                atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                        animated:NO];
} completion:^(BOOL finished) {
    NSLog(@"Completed");
}];

当前可见的单元格消失,只创建目标单元格。我在 collectionView:cellForItemAtIndexPath: 方法中包含了相同的日志记录:

Transition
Cell Created for Index Path: <NSIndexPath 0x71702f0> 2 indexes [3, 3]
Completed

【问题讨论】:

  • 您是否尝试将动画设置为 NO,然后将其包裹在 UIView animateWithDuration 中?这就是我为我的滚动视图动画之一做的事情。我做[UIView animtateWithDuration ... [scrollView scrollToRect..
  • 是的。不幸的是,这搞砸了单元格的创建。它滚动 - 但只显示动画中的第一个和最后一个 UICollectionViewsCell。
  • 只是出于好奇,您是否也尝试过暴力破解您的块中的动画。 [UIView animateWithDuration:.... animations:^{ [self.colectionView scrollToItemAtIndexPath:[0, 1]; self.collectionView.scrollToItemAtIndexpath[0,2];....self.collectionView.scrollToItemAtIndexPath[3,3];
  • 似乎没有任何计时器等的唯一方法是调用objc_msgSend(self.collectionView, @selector(_setContentOffsetAnimationDuration:), 10.0),其中_setContentOffsetAnimationDuration:似乎是私有API的一部分......
  • 虽然这不是一个答案,但它至少可以为您的第二种情况提供一些启示:您观察到的是优化工作。如果 iOS 无论如何都不会显示它们,为什么 应该 创建中间单元格(动画:否)。因此,您只需创建最后一个单元格并切换到该单元格 - 记住视图不知道您正在“从外部”为其设置动画;)

标签: iphone core-animation uicollectionview


【解决方案1】:

我在UITableView 遇到了类似的问题,我通过以下代码解决了这个问题:

[CATransaction begin];
[CATransaction setCompletionBlock:onCompletion];
[CATransaction setAnimationDuration:duration];

[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
                            atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                    animated:YES];

[CATransaction commit];

显然,不能用animated:NO 调用它,因为方法内的动画代码很重要。使用 CATransaction 包装动画对我有用。

【讨论】:

  • 不幸的是,不 - 这不起作用。在这种情况下,动画确实发生了 - 但在预定义的持续时间(不是在 setAnimationDuration: 方法中设置的持续时间。
  • 谢谢这对我有帮助
  • 您可以使用- [UIView animateWithDuration: animations: completion:] 以更少的代码获得相同的行为。
  • @orkoden 实际上没有。 UIView 动画和核心动画不是一回事。但我想UIView 动画可以在核心动画不起作用的地方工作。
【解决方案2】:

对我来说这是可行的。 显然它需要一些调整(以获得更准确的时间并使其反向滚动,从下到上。现在它只支持从上到下的垂直滚动)

这样调用:

[self scrollToIndexPath:[NSIndexPath indexPathForItem:40 inSection:0] withAnimationDuration:3.0f];

这是代码

-(void)scrollToIndexPath:(NSIndexPath *)path withAnimationDuration:(float)duration
{
    NSIndexPath *firstCell = [[self.collectionView indexPathsForVisibleItems] objectAtIndex:0];
    UICollectionViewLayoutAttributes *attributesForFirstCell = [self.collectionView layoutAttributesForItemAtIndexPath:firstCell];
    CGRect firstCellRect = attributesForFirstCell.frame;
    CGPoint startPoint = firstCellRect.origin;

    NSIndexPath *destinationCell = path;
    UICollectionViewLayoutAttributes *attributesForDestCell = [self.collectionView layoutAttributesForItemAtIndexPath:destinationCell];
    CGRect destCellRect = attributesForDestCell.frame;
    CGPoint destPoint = destCellRect.origin;

    self.destination = destPoint;

    float delta = destPoint.y - startPoint.y;

    float cycle = (delta / (50*duration));
    self.pass = (int)cycle + 1;

    self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(scrollView) userInfo:nil repeats:YES];
}



- (void) scrollView {

    float w = self.pass;

    CGPoint scrollPoint = self.collectionView.contentOffset;
    scrollPoint.y = scrollPoint.y + w;

    if (scrollPoint.y >= self.destination.y)
        [self.myTimer invalidate];
    [self.collectionView setContentOffset: scrollPoint animated: NO];
}

【讨论】:

  • 我建议使用 CADisplayLink 而不是 NSTimer。 CADisplayLink 自动触发一次/系统框架。
【解决方案3】:

我可以通过使用动画 false 将它包装在 UIView.animate 中来使其工作:

UIView.animate(withDuration: 0.7, delay: 0.0, options: .curveEaseInOut, animations: {
            self.collectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .centeredHorizontally, animated: false)
        }, completion: nil)

【讨论】:

    【解决方案4】:

    如果你把一些代码放在scrollViewDidScroll: 里呢?

    我有一个类似的问题,我通过调用selectItemAtIndexPath:animated:scrollPosition 然后使用scrollViewDidScroll: 来运行我通常在完成块中运行的东西。

    当然,您可能必须跟踪一个或两个 BOOL 来决定是否需要在 scrollViewDidScroll: 中执行任何操作。

    【讨论】:

      【解决方案5】:

      您可以使用 AnimationEngine 库干净地完成此操作。它以基于块的动画语法包装了CADisplayLink。我发布了一个答案here,其中包含一个动画contentOffset 的代码示例。您只需要做从 indexPath 到 contentOffset 的转换。

      【讨论】:

        【解决方案6】:

        我找到了一种手动滚动并完全绕过self.collectionView scrollToItemAtIndexPath ..

        我还尝试使用完成块来循环浏览不同的部分,但这导致了生涩的体验。

        请注意,此示例垂直滚动——您应该能够将其更改为水平滚动。您可能还必须调整偏移量,以便滚动在所需位置停止。同样,令我惊讶的是 API 没有提供控制速度的方法。

        -(void)scrollMethod {
        
            // Find the point where scrolling should stop.
            UICollectionViewLayoutAttributes *attr = [self.collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]];
        
            CGRect cellRect = attr.frame;
        
            self.source = self.collectionView.frame.origin;
            self.destination = cellRect.origin;
            self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(scrollOn) userInfo:nil repeats:YES];
        
        }
        
        -(void)scrollOn {
            self.collectionView.contentOffset = self.source;
            // If we have crossed where we need to be, quit the timer
            if ( self.source.y > self.destination.y)
                [self.myTimer invalidate];
        
            self.source = CGPointMake(self.source.x, self.source.y+1);
        }
        

        【讨论】:

        • @Lifely 如果您确实提出了一些有用的建议,而不是投反对票和制造冷嘲热讽,这可能会有所帮助。上面的解决方案确实有效,我还活着:-)
        • @Lifely - 实际上,对于某些类型的滚动逻辑,计时器可能是最佳实践。请参阅 John Resig(jQuery 的创建者)的博客:ejohn.org/blog/learning-from-twitter
        【解决方案7】:

        实际的解决方案是您需要在主队列中执行此 scrollToItemAtIndexPath 。这样只有你才能得到它的实际工作。

        示例代码:

         dispatch_async(dispatch_get_main_queue(), ^{
        
            [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
        

        });

        【讨论】:

          猜你喜欢
          • 2012-10-07
          • 2018-06-15
          • 2014-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-29
          • 1970-01-01
          相关资源
          最近更新 更多