保持contentOffset在UICollectionView同时旋转接口方向(Keeping t

2019-07-04 00:41发布

我想处理的UICollectionViewController界面取向的变化。 我想要实现的是,我想有一个接口旋转后相同 contentOffset。 这意味着,它应当对应于边界变化的比率来改变。

在纵向与内容的偏移开始{bounds.size.width * 2,0} ...

...应该导致到内容在景观与{bounds.size.width * 2,0}(反之亦然)的偏移量也。

计算新的偏移量是没有问题的,但不知道在哪里(或者)来设置它,以获得平滑的动画。 我在做什么这样的票价无效布局willRotateToInterfaceOrientation:duration:和重置内容偏移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:但这会导致到一个非常奇怪的行为。

一个例子可以在我的项目中找到GitHub上 。

Answer 1:

下面是代码雨燕3.1和相同工作的雨燕4.2

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)
}


Answer 2:

解决方案1,“刚扣”

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

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

但是,你要面对的问题是,对于过渡动画是非常奇怪的。 我在做什么我的情况下(这是因为你几乎是相同的)是:

溶液2中,“平滑的动画”

1)首先,我设置单元格的大小,这可以通过的CollectionView进行管理:布局:sizeForItemAtIndexPath:委托方法如下:

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

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

2)当设备即将旋转,我将与所有调整口罩集合视图顶部的ImageView的。 此视图实际上将隐藏的CollectionView古怪(因为它是在它的上面),并且由于所述willRotatoToInterfaceOrientation:方法被调用动画块内它会相应地旋转。 我还保持未来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)最后,最后一步是“啪”的内容偏移到有效的页面,并删除临时ImageView的。

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


Answer 3:

“公正卡”上面的回答对我来说,因为它往往没有上,这是鉴于旋转之前的项目最终没有奏效。 因此,我衍生使用的焦点项目(如果设置),用于计算所述内容偏移的流布局。 我设置willAnimateRotationToInterfaceOrientation的项目,并在didRotateFromInterfaceOrientation清除。 插图调整似乎需要在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


Answer 4:

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

现在,你应该使用以下命令:

/* 
This method is called when the view controller's view's size is changed by its parent (i.e. 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
    }];
}

斯威夫特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
    }
}


Answer 5:

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

从文档:

在布局过程中更新或布局之间转换时,集合视图调用此方法来给你更改建议的内容偏移在动画的最后机会使用。 您可能会覆盖该方法适用于动画或过渡可能导致项目被定位在一个方式,是不是最适合你的设计。



Answer 6:

这个问题困扰了我一点为好。 得分最高的回答显得有点太哈克对我,所以我只是简单化下来一点,旋转前后只是改变集合视图的阿尔法分别。 我也不动画内容偏移的更新。

- (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;
}

还算顺利,少哈克。



Answer 7:

我使用FZ的变体。 答案(的iOS 7&8):

循环之前:

  1. 存储当前可见的索引路径
  2. 创建的CollectionView的快照
  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]; } 


Answer 8:

上捎带关闭troppoli的解决方案,您可以设置自定义类的偏移量,而不必担心记住要在您的视图控制器的代码。 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


Answer 9:

这项工作就像一个魅力:

-(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];
}];
}


Answer 10:

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

因此可见UICollectionViewCell始终没有预期的位置定位。

我们预计形象,遵循可见UICollectionView

方向,我们预计

UICollectionView必须委托功能『UICollectionViewDelegateFlowLayout』的[的CollectionView sizeForItemAtIndexPath]。

你应该在这个函数计算的商品尺寸。

自定义UICollectionViewFlowLayout必须重写的功能如下。

  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]

但『willRotateToInterfaceOrientation』已被弃用iOS中9,或者你可以拨打差异的方式函数[XXXCollectionVew.collectionViewLayout的invalidateLayout。

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



Answer 11:

如果发现使用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方法来确定要滚动并willAnimationRotationToInterfaceOrientation重新计算它的视图的一部分时,认为已经改变它的大小(当这个方法是由框架调用的界限已经改变)和实际上滚动到新的位置,而不动画。 在我的代码使用的索引路径,第一视觉细胞要做到这一点,但contentOffset.y / contentSize.height的比例也将做的工作稍微不同的方式。



Answer 12:

什么工作对我来说是这样的:

  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() } } 

上面的代码是斯威夫特 ,但你明白了吧,很容易给“翻译”



Answer 13:

在斯威夫特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视野的宽度。



Answer 14:

你可能想隐藏的CollectionView在它的(不正确)的动画和显示旋转正确,而不是该小区的占位符视图。

对于一个简单的照相馆我发现了一个办法做到这一点,看起来相当不错。 看到这里我的答案: 如何旋转,类似相册应用UICollectionView并保持为中心的当前看法?



Answer 15:

我的方法是使用一个UICollectionViewFlowlayout对象。

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

[flowLayout setMinimumLineSpacing:26.0f];

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

[flowLayout setMinimumInteritemSpacing:0.0f];

请注意,当你旋转屏幕,它的行为不同。 就我而言,我有这么minimumlinespacing是26.0f它水平滚动。 然后,它似乎太可怕了,当它旋转到横向方向。 我要检查旋转并设置minimumlinespacing为方向0.0F作出正确选择。

而已! 简单。



Answer 16:

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

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

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

然后检查它对于每个方向和使用您的配置每个方向。



Answer 17:

-(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); }

这样,您就可以调整内容偏移和你的大小。



Answer 18:

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

实施collectionView:layout:sizeForItemAtIndexPath:方法<CollectionViewDelegateFlowLayout>和方法验证接口方向和应用每一个细胞的自定义大小。

- (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);

    }

}


Answer 19:

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

- (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的视图。 在上海华我也这样做

- (void)setFrame:(CGRect)frame
{    
    UICollectionViewFlowLayout *collectionViewFlowLayout = (UICollectionViewFlowLayout *)[_collectionView collectionViewLayout];

    [collectionViewFlowLayout setItemSize:frame.size];

    [super setFrame:frame];
}

这是为了调整单元尺寸为全屏(全视角是精确的;))。 如果你不这样做,在这里有很多的错误信息可能会出现关于该小区大小比的CollectionView做大,对这个行为是没有定义和唧唧歪歪.....

这些的方法可以偏离方向被合并到的CollectionView的一个子类,或者在包含的CollectionView的看法,但我目前的计划是这个去的合乎逻辑的方式。



Answer 20:

“公正啪”的答案是正确的做法,并不需要用快照覆盖IMO额外的平滑。 但是有这解释了为什么有些人看到,在某些情况下,正确的页面不滚动到的问题。 计算页面,你要使用的高度,而不是宽度。 为什么? 由于视图几何已通过的时间已经旋转targetContentOffsetForProposedContentOffset叫,还等什么是宽度是现在的高度。 此外四舍五入比天花板更明智。 所以:

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


Answer 21:

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

  1. 计算当前滚动的NSIndexPath
  2. 禁用滚动和分页在UICollectionView
  3. 应用新的流式布局,以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];
}

我希望这有帮助。



Answer 22:

我已经得到了一些麻烦animateAlongsideTransitionanimateAlongsideTransition (见下面的代码)。

注意,它被称为时(而不是之前)的动画我的任务是更新使用滚动顶端可见行(我面临着在iPad上的问题,当表视图细胞转移设备时,表视图滚动位置旋转,所以我创立该问题的解决方案)。 但可能是它会为contentOffset是有用的。

我试图通过以下方式解决问题:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    __weak TVChannelsListTableViewController *weakSelf = self;

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        weakSelf.topVisibleRowIndexPath = [[weakSelf.tableView indexPathsForVisibleRows] firstObject];
    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        [weakSelf.tableView scrollToRowAtIndexPath:weakSelf.topVisibleRowIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
    }];
}

但它没有工作。 例如,顶部的CEL索引路径为(0,20)。 但是,当设备旋转animateAlongsideTransition块被称为和[[weakSelf.tableView indexPathsForVisibleRows] firstObject]返回的索引路径(0,27)。

我认为这个问题是在检索索引路径weakSelf 。 因此,要解决我搬到这个问题self.topVisibleRowIndexPath[coordinator animateAlongsideTransition: completion]方法调用:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    __weak TVChannelsListTableViewController *weakSelf = self;
    self.topVisibleRowIndexPath = [[weakSelf.tableView indexPathsForVisibleRows] firstObject];

    [coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        [weakSelf.tableView scrollToRowAtIndexPath:weakSelf.topVisibleRowIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
    }];
}

而且我发现另一个有趣的事情是过时方法willRotateToInterfaceOrientationwillRotateToInterfaceOrientation仍然成功堪称后来的iOS 8.0时方法viewWillTransitionToSize不重新定义。

所以其他的方式来解决我的情况下,问题是使用的方法已过时,而不是新的。 我认为这是不对的解决方案,但可以尝试,如果其他方面不工作:)



Answer 23:

雨燕4.2的子类:

class RotatableCollectionViewFlowLayout: UICollectionViewFlowLayout {

    private var focusedIndexPath: IndexPath?

    override func prepare(forAnimatedBoundsChange oldBounds: CGRect) {
        super.prepare(forAnimatedBoundsChange: oldBounds)
        focusedIndexPath = collectionView?.indexPathsForVisibleItems.first
    }

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
        guard let indexPath = focusedIndexPath
            , let attributes = layoutAttributesForItem(at: indexPath)
            , let collectionView = collectionView else {
                return super.targetContentOffset(forProposedContentOffset: proposedContentOffset)
        }
        return CGPoint(x: attributes.frame.origin.x - collectionView.contentInset.left,
                       y: attributes.frame.origin.x - collectionView.contentInset.left)
    }

    override func finalizeAnimatedBoundsChange() {
        super.finalizeAnimatedBoundsChange()
        focusedIndexPath = nil
    }
}


Answer 24:

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

- (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];
     }];
}


文章来源: Keeping the contentOffset in a UICollectionView while rotating Interface Orientation