我尝试设置持续时间(使用我会尝试的常规方法)来设置UICollectionView的selectItemAtIndexPath:animated:scrollPosition:
方法(或scrollToItemAtIndexPath:atScrollPosition:animated:
方法)的动画持续时间。我已经尝试了[UIView setAnimationDuration]
,我尝试将其包装在CATransaction
中。在改变动画持续时间方面我一直没有成功(虽然我承认我可能在这个逻辑上犯了错误。)
思想?
更新:
我在这里尝试了很多方法。最接近的解决方案是执行我们通常对UIScrollView
动画执行的操作(通过将animated:参数设置为NO
并将其包装在UIView
动画块中)。这适用于scrollview。但是,由于某种原因,这会导致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
答案 0 :(得分:5)
我遇到与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
包装动画为我工作。
答案 1 :(得分:1)
对我而言,这是有效的。 显然它需要一些调整(以获得更准确的时间并使其从底部到顶部反向滚动。到目前为止它只支持从上到下的垂直滚动)
请拨打以下内容:
[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];
}
答案 2 :(得分:0)
如果您在scrollViewDidScroll:
中添加了一些代码,该怎么办?
我遇到类似的问题,我通过调用selectItemAtIndexPath:animated:scrollPosition
然后使用scrollViewDidScroll:
来运行我通常在完成块中运行的内容来解决。
当然,您可能需要跟踪BOOL
或者两个scrollViewDidScroll:
,以确定您需要执行{{1}}中的任何内容。
答案 3 :(得分:0)
您可以使用AnimationEngine库干净利落地完成此操作。它在基于块的动画语法中包装CADisplayLink
。我发布了一个答案here,其中包含动画contentOffset
的代码示例。您只需要执行从indexPath到contentOffset的转换。
答案 4 :(得分:0)
我可以通过将其包装在UIView.animate中并使其具有动画 false :
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)
答案 5 :(得分:-1)
我找到了一种手动滚动并完全绕过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);
}
答案 6 :(得分:-3)
实际解决方案是您需要在主队列中执行scrollToItemAtIndexPath。所以只有你才能得到它的实际工作。
示例代码:
dispatch_async(dispatch_get_main_queue(), ^{
[collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
});