在旋转界面方向的同时将contentOffset保留在UICollectionView中

我正在尝试处理UICollectionViewController中的界面方向更改。 我试图实现的是,我想有一个接口旋转后相同的 contentOffset。 意思是说,它应该根据边界比率的变化而改变。

从纵向开始,内容偏移量为{ bounds.size.width * 2,0} …

UICollectionView在portait

…应该导致在横向上的内容偏移{ bounds.size.width * 2,0}(反之亦然)。

横向UICollectionView

计算新的偏移量不是问题,但不知道在哪里(或何时)设置它,以获得平滑的animation。 我正在做这样的票价是无效的willRotateToInterfaceOrientation:duration:并重置didRotateFromInterfaceOrientation:的内容偏移didRotateFromInterfaceOrientation:

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration; { self.scrollPositionBeforeRotation = CGPointMake(self.collectionView.contentOffset.x / self.collectionView.contentSize.width, self.collectionView.contentOffset.y / self.collectionView.contentSize.height); [self.collectionView.collectionViewLayout invalidateLayout]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation; { CGPoint newContentOffset = CGPointMake(self.scrollPositionBeforeRotation.x * self.collectionView.contentSize.width, self.scrollPositionBeforeRotation.y * self.collectionView.contentSize.height); [self.collectionView newContentOffset animated:YES]; } 

这将改变旋转后的内容偏移量。

如何在旋转过程中设置它? 我尝试在willAnimateRotationToInterfaceOrientation:duration:设置新的内容偏移量willAnimateRotationToInterfaceOrientation:duration:但是这会导致一个非常奇怪的行为。

一个例子可以在我的GitHub项目中find 。

解决scheme1,“只是捕捉”

如果您只需要确保contentOffset以正确的位置结束,则可以创buildUICollectionViewLayout的子类并实现targetContentOffsetForProposedContentOffset:方法。 例如,你可以做这样的事情来计算页面:

 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset { NSInteger page = ceil(proposedContentOffset.x / [self.collectionView frame].size.width); return CGPointMake(page * [self.collectionView frame].size.width, 0); } 

但是,你将面临的问题是,这个过渡的animation是非常奇怪的。 我对我的案子(与你们几乎一样)做的是:

解决scheme2,“stream畅的animation”

1)首先我设置单元格大小,可以通过collectionView:layout:sizeForItemAtIndexPath: delegate方法来pipe理,如下所示:

 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.view bounds].size; } 

请注意,[self.view界限]会根据设备旋转而改变。

2)当设备即将旋转,我添加一个imageView的集合视图顶部与所有resize的面具。 这个视图实际上会隐藏collectionView的怪异(因为它位于顶部),并且由于willRotatoToInterfaceOrientation:方法在一个animation块中被调用,它将相应地旋转。 我也保持下一个contentOffset根据显示的indexPath,所以我可以修复一旦旋转完成contentOffset:

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { // Gets the first (and only) visible cell. NSIndexPath *indexPath = [[self.collectionView indexPathsForVisibleItems] firstObject]; KSPhotoViewCell *cell = (id)[self.collectionView cellForItemAtIndexPath:indexPath]; // Creates a temporary imageView that will occupy the full screen and rotate. UIImageView *imageView = [[UIImageView alloc] initWithImage:[[cell imageView] image]]; [imageView setFrame:[self.view bounds]]; [imageView setTag:kTemporaryImageTag]; [imageView setBackgroundColor:[UIColor blackColor]]; [imageView setContentMode:[[cell imageView] contentMode]]; [imageView setAutoresizingMask:0xff]; [self.view insertSubview:imageView aboveSubview:self.collectionView]; // Invalidate layout and calculate (next) contentOffset. contentOffsetAfterRotation = CGPointMake(indexPath.item * [self.view bounds].size.height, 0); [[self.collectionView collectionViewLayout] invalidateLayout]; } 

请注意,我的UICollectionViewCell的子类有一个公共imageView属性。

3)最后,最后一步是将内容偏移量“捕捉”到有效页面,并删除临时图像视图。

 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self.collectionView setContentOffset:contentOffsetAfterRotation]; [[self.view viewWithTag:kTemporaryImageTag] removeFromSuperview]; } 

上面的“简单”答案对我来说不起作用,因为它经常不会在旋转之前看到的项目结束。 所以我派生了一个stream程布局,使用焦点项目(如果设置)来计算内容偏移量。 我在willAnimateRotationToInterfaceOrientation中设置项目,并在didRotateFromInterfaceOrientation中清除它。 embedded式调整似乎是IOS7上的需要,因为集合视图可以在顶部栏下布局。

 @interface HintedFlowLayout : UICollectionViewFlowLayout @property (strong)NSIndexPath* pathForFocusItem; @end @implementation HintedFlowLayout -(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset { if (self.pathForFocusItem) { UICollectionViewLayoutAttributes* layoutAttrs = [self layoutAttributesForItemAtIndexPath:self.pathForFocusItem]; return CGPointMake(layoutAttrs.frame.origin.x - self.collectionView.contentInset.left, layoutAttrs.frame.origin.y-self.collectionView.contentInset.top); }else{ return [super targetContentOffsetForProposedContentOffset:proposedContentOffset]; } } @end 

对于那些使用iOS 8+, willRotateToInterfaceOrientationdidRotateFromInterfaceOrientation已被弃用。

您现在应该使用以下内容:

 /* This method is called when the view controller's view's size is changed by its parent (ie for the root view controller when its window rotates or is resized). If you override this method, you should either call super to propagate the change to children or manually forward the change to children. */ - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { // Update scroll position during rotation animation self.collectionView.contentOffset = (CGPoint){contentOffsetX, contentOffsetY}; } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { // Whatever you want to do when the rotation animation is done }]; } 

Swift 3:

 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: { (context:UIViewControllerTransitionCoordinatorContext) in // Update scroll position during rotation animation }) { (context:UIViewControllerTransitionCoordinatorContext) in // Whatever you want to do when the rotation animation is done } } 

我认为正确的解决scheme是重写- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset方法在子类UICollectionViewFlowLayout

从文档:

在布局更新期间,或在布局之间转换时,集合视图会调用此方法,以使您有机会更改在animation结尾处使用的build议内容偏移量。 如果animation或转换可能导致项目的定位方式不适合您的devise,则可能会覆盖此方法。

这里是Swift 3.1中的代码

 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) let offset = self.collectionView?.contentOffset; let width = self.collectionView?.bounds.size.width; let index = round(offset!.x / width!); let newOffset = CGPoint(x: index * size.width, y: offset!.y) self.collectionView?.setContentOffset(newOffset, animated: false) coordinator.animate(alongsideTransition: { (context) in self.collectionView?.reloadData() self.collectionView?.setContentOffset(newOffset, animated: false) }, completion: nil) } 

这个问题困扰了我一下。 回答得最多的回答对我来说似乎有点太过分了,所以我只是简单地把它弄昏了一下,只是在回转之前和之后分别改变集合视图的alpha值。 我也不animation的内容偏移更新。

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { self.collectionView.alpha = 0; [self.collectionView.collectionViewLayout invalidateLayout]; self.scrollPositionBeforeRotation = CGPointMake(self.collectionView.contentOffset.x / self.collectionView.contentSize.width, self.collectionView.contentOffset.y / self.collectionView.contentSize.height); } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation; { CGPoint newContentOffset = CGPointMake(self.scrollPositionBeforeRotation.x * self.collectionView.contentSize.width, self.scrollPositionBeforeRotation.y * self.collectionView.contentSize.height); [self.collectionView setContentOffset:newContentOffset animated:NO]; self.collectionView.alpha = 1; } 

相当平稳,lesshacky。

我使用fz的变体。 回答(iOS 7和8):

轮换之前:

  1. 存储当前可见的索引path
  2. 创buildcollectionView的快照
  3. 将UIImageView放在集合视图的顶部

旋转后:

  1. 滚动到存储的索引
  2. 删除图像视图。

     @property (nonatomic) NSIndexPath *indexPath; - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { self.indexPathAfterRotation = [[self.collectionView indexPathsForVisibleItems] firstObject]; // Creates a temporary imageView that will occupy the full screen and rotate. UIGraphicsBeginImageContextWithOptions(self.collectionView.bounds.size, YES, 0); [self.collectionView drawViewHierarchyInRect:self.collectionView.bounds afterScreenUpdates:YES]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; [imageView setFrame:[self.collectionView bounds]]; [imageView setTag:kTemporaryImageTag]; [imageView setBackgroundColor:[UIColor blackColor]]; [imageView setContentMode:UIViewContentModeCenter]; [imageView setAutoresizingMask:0xff]; [self.view insertSubview:imageView aboveSubview:self.collectionView]; [[self.collectionView collectionViewLayout] invalidateLayout]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self.collectionView scrollToItemAtIndexPath:self.indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; [[self.view viewWithTag:kTemporaryImageTag] removeFromSuperview]; } 

这项工作就像一个魅力:

 -(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return self.view.bounds.size; } -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { int currentPage = collectionMedia.contentOffset.x / collectionMedia.bounds.size.width; float width = collectionMedia.bounds.size.height; [UIView animateWithDuration:duration animations:^{ [self.collectionMedia setContentOffset:CGPointMake(width * currentPage, 0.0) animated:NO]; [[self.collectionMedia collectionViewLayout] invalidateLayout]; }]; } 

旋转界面方向后,UICollectionViewCell通常会移动到另一个位置,因为我们不会更新contentSize和contentOffset。

所以可见的UICollectionViewCell总是不在预期的位置。

我们期待的形象的可见的UICollectionView如下

我们所期望的方向

UICollectionView必须委托“UICollectionViewDelegateFlowLayout”的函数[collectionView sizeForItemAtIndexPath]。

你应该在这个函数中计算项目大小。

自定义的UICollectionViewFlowLayout必须覆盖如下function。

  1. -(void)prepareLayout

    。 设置itemSize,scrollDirection和其他。

  2. -(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity

    。 计算页码或计算可见内容偏移量。

  3. -(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset

    。 返回视觉内容偏移。

  4. -(CGSize)collectionViewContentSize

    。 返回collectionView的总内容大小。

你的viewController必须重写“willRotateToInterfaceOrientation”,在这个函数中你应该调用函数[XXXCollectionVew.collectionViewLayout invalidateLayout];

但在iOS 9中不推荐使用“willRotateToInterfaceOrientation”,也可以以不同的方式调用函数[XXXCollectionVew.collectionViewLayout invalidateLayout]。

有一个例子如下: https : //github.com/bcbod2002/CollectionViewRotationTest

为了回到troppoli的解决scheme,您可以在自定义类中设置偏移量,而不必担心记住在视图控制器中实现代码。 prepareForAnimatedBoundsChange应当在旋转设备时调用,然后在完成旋转后调用finalizeAnimatedBoundsChange

 @interface OrientationFlowLayout () @property (strong)NSIndexPath* pathForFocusItem; @end @implementation OrientationFlowLayout - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset { if (self.pathForFocusItem) { UICollectionViewLayoutAttributes* layoutAttrs = [self layoutAttributesForItemAtIndexPath: self.pathForFocusItem]; return CGPointMake(layoutAttrs.frame.origin.x - self.collectionView.contentInset.left, layoutAttrs.frame.origin.y - self.collectionView.contentInset.top); } else { return [super targetContentOffsetForProposedContentOffset:proposedContentOffset]; } } - (void)prepareForAnimatedBoundsChange:(CGRect)oldBounds { [super prepareForAnimatedBoundsChange:oldBounds]; self.pathForFocusItem = [[self.collectionView indexPathsForVisibleItems] firstObject]; } - (void)finalizeAnimatedBoundsChange { [super finalizeAnimatedBoundsChange]; self.pathForFocusItem = nil; } @end 

如果发现使用targetContentOffsetForProposedContentOffset在所有情况下都不起作用,并且使用didRotateFromInterfaceOrientation的问题是它会给出可视的构件。 我完美的工作代码如下:

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; _indexPathOfFirstCell = [self indexPathsForVisibleItems].firstObject; } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; if (_indexPathOfFirstCell) { [UIView performWithoutAnimation:^{ [self scrollToItemAtIndexPath:self->_indexPathOfFirstCell atScrollPosition:UICollectionViewScrollPositionTop animated:NO]; }]; _indexPathOfFirstCell = nil; } } 

关键是使用willRotateToInterfaceOrientation方法来确定视图中您要滚动的部分,并在视图发生变化时重新计算视图中的部分(当框架调用此方法时,边界已经更改),以及实际上滚动到新的位置没有animation。 在我的代码中,我使用第一个可视化单元的索引path来做到这一点,但contentOffset.y / contentSize.height的百分比也会以稍微不同的方式完成工作。

您可能希望在(不正确)animation期间隐藏collectionView,并显示正确旋转的单元格的占位符视图。

对于一个简单的照片库,我find了一个方法来做到这一点,看起来不错。 看到我的答案在这里: 如何旋转UICollectionView类似的照片应用程序,并保持当前视图居中?

我的方法是使用UICollectionViewFlowlayout对象。

如果水平滚动,则设置ojbect行距。

 [flowLayout setMinimumLineSpacing:26.0f]; 

如果垂直滚动,请设置其间距间距。

 [flowLayout setMinimumInteritemSpacing:0.0f]; 

注意,当你旋转屏幕时,它的行为会有所不同。 在我的情况下,我把它水平滚动,所以minimumlinespacing是26.0f。 然后,当它转向风景方向时,它看起来很可怕。 我必须检查旋转,并为该方向0.0f设置minimumlinespacing,以使其正确。

而已! 简单。

我有我的项目的问题,我用UICollectionView两个不同的布局。

 mCustomCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"LandScapeCell" forIndexPath:indexPath]; theCustomCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"PortraitCell" forIndexPath:indexPath]; 

然后检查每个方向,并针对每个方向使用您的configuration。

 -(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { CGSize pnt = CGSizeMake(70, 70); return pnt; } -(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { // UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>) return UIEdgeInsetsMake(3, 0, 3, 0); } 

这样您可以调整内容偏移量和单元格的大小。

使用<CollectionViewDelegateFlowLayout>和方法didRotateFromInterfaceOrientation:重新加载CollectionView的数据。

实现collectionView:layout:sizeForItemAtIndexPath: <CollectionViewDelegateFlowLayout>方法,并在方法中validation接口方向并应用每个单元格的自定义大小。

 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; if (UIInterfaceOrientationIsPortrait(orientation)) { return CGSizeMake(CGFloat width, CGFloat height); } else { return CGSizeMake(CGFloat width, CGFloat height); } } 

我有一个类似的情况下,我用这个

 - (void)setFrame:(CGRect)frame { CGFloat currentWidth = [self frame].size.width; CGFloat offsetModifier = [[self collectionView] contentOffset].x / currentWidth; [super setFrame:frame]; CGFloat newWidth = [self frame].size.width; [[self collectionView] setContentOffset:CGPointMake(offsetModifier * newWidth, 0.0f) animated:NO]; } 

这是一个包含一个collectionView的视图。 在superview我也做到这一点

 - (void)setFrame:(CGRect)frame { UICollectionViewFlowLayout *collectionViewFlowLayout = (UICollectionViewFlowLayout *)[_collectionView collectionViewLayout]; [collectionViewFlowLayout setItemSize:frame.size]; [super setFrame:frame]; } 

这是调整单元格大小为全屏(完整视图是确切的;))。 如果你不这样做这里很多错误信息可能会出现关于单元格大小比collectionview更大的行为,这是没有定义和bla bla bla …..

这些方法可以合并到collectionview的一个子类中,或者在包含collectionview的视图中,但是对于我当前的项目来说,这是合乎逻辑的方法。

“简单”的答案是正确的做法,并不需要额外的平滑快照叠加海事组织。 但是有一个问题可以解释为什么有些人看到在某些情况下正确的页面没有滚动。 计算页面时,你会想使用高度而不是宽度。 为什么? 由于视图几何体已经旋转了targetContentOffsetForProposedContentOffset被调用的时间,所以宽度现在是高度。 四舍五入比天花板更明智。 所以:

 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset { NSInteger page = round(proposedContentOffset.x / self.collectionView.bounds.size.height); return CGPointMake(page * self.collectionView.bounds.size.width, 0); } 

这对我来说是什么工作:

  1. 从我的UICollectionViewDelegateFlowLayout方法中设置我的单元格的大小

     func collectionView(collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize { return collectionView.bounds.size } 
  2. 之后我实现了willRotateToInterfaceOrientationToInterfaceOrientation:duration:像这样

     override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { let currentPage = Int(collectionView.contentOffset.x / collectionView.bounds.size.width) var width = collectionView.bounds.size.height UIView.animateWithDuration(duration) { self.collectionView.setContentOffset(CGPointMake(width * CGFloat(currentPage), 0.0), animated: false) self.collectionView.collectionViewLayout.invalidateLayout() } } 

上面的代码是在Swift中,但是你明白了,很容易“翻译”

我用下面的步骤解决了这个问题:

  1. 计算当前滚动的NSIndexPath
  2. 禁用UICollectionView中的滚动和分页
  3. 将新的stream布局应用于UICollectionView
  4. 在UICollectionView中启用滚动和分页
  5. 将UICollectionView滚动到当前的NSIndexPath

以下是演示上述步骤的代码模板:

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration; { //Calculating Current IndexPath CGRect visibleRect = (CGRect){.origin = self.yourCollectionView.contentOffset, .size = self.yourCollectionView.bounds.size}; CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect)); self.currentIndexPath = [self.yourCollectionView indexPathForItemAtPoint:visiblePoint]; //Disable Scrolling and Pagination [self disableScrolling]; //Applying New Flow Layout [self setupNewFlowLayout]; //Enable Scrolling and Pagination [self enableScrolling]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation; { //You can also call this at the End of `willRotate..` method. //Scrolling UICollectionView to current Index Path [self.yourCollectionView scrollToItemAtIndexPath:self.currentIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO]; } - (void) disableScrolling { self.yourCollectionView.scrollEnabled = false; self.yourCollectionView.pagingEnabled = false; } - (void) enableScrolling { self.yourCollectionView.scrollEnabled = true; self.yourCollectionView.pagingEnabled = true; } - (void) setupNewFlowLayout { UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc] init]; flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0); flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal; flowLayout.minimumInteritemSpacing = 0; flowLayout.minimumLineSpacing = 0; [flowLayout setItemSize:CGSizeMake(EXPECTED_WIDTH, EXPECTED_HEIGHT)]; [self.yourCollectionView setCollectionViewLayout:flowLayout animated:YES]; [self.yourCollectionView.collectionViewLayout invalidateLayout]; } 

我希望这有帮助。

在Swift 3。

你应该跟踪哪些单元格项(页面)正在呈现之前旋转indexPath.item,X坐标或其他。 然后,在你的UICollectionView:

 override func collectionView(_ collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { let page:CGFloat = pageNumber // your tracked page number eg. 1.0 return CGPoint(x: page * collectionView.frame.size.width, y: -(topInset)) //the 'y' value would be '0' if you don't have any top EdgeInset } 

在我的情况下,我使viewDidLayoutSubviews()中的布局无效,因此collectionView.frame.size.width是已旋转的collectionVC视图的宽度。

你可能想试试这个未经testing的代码:

 - (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) toInterfaceOrientation duration: (NSTimeInterval) duration { [UIView animateWithDuration: duration animation: ^(void) { CGPoint newContentOffset = CGPointMake(self.scrollPositionBeforeRotation.x * self.collectionView.contentSize.height, self.scrollPositionBeforeRotation.y * self.collectionView.contentSize.width); [self.collectionView setContentOffset: newContentOffset animated: YES]; }]; }