Сохранение содержимогоОфис в UICollectionView при вращении Ориентация интерфейса

Я пытаюсь обрабатывать изменения ориентации интерфейса в UICollectionViewController. То, что я пытаюсь достичь, заключается в том, что я хочу иметь тот же контент, что и после поворота интерфейса. Это означает, что он должен быть изменен в соответствии с отношением изменений границ.

Начиная с портрета с смещением содержимого {bounds.size.width * 2, 0}...

UICollectionView in portait

... должно приводить к смещению содержимого в ландшафте также с помощью {bounds.size.width * 2, 0} (и наоборот).

UICollectionView in landscape

Вычисление нового смещения не является проблемой, но не знает, где (или когда) установить его, чтобы получить гладкую анимацию. То, что я делаю так, - это недействительность макета в 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.

Ответ 1

Решение 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: layout: sizeForItemAtIndexPath: delegate следующим образом:

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

Обратите внимание, что [self.view bounds] изменится в соответствии с вращением устройства.

2) Когда устройство вот-вот начнет вращаться, я добавляю imageView поверх представления коллекции со всеми масками для изменения размера. Это представление фактически скроет weirdness 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) Наконец, последний шаг - "привязать" смещение содержимого к допустимой странице и удалить временное изображение.

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

Ответ 2

Ответ "просто щелкнуть" выше не работал у меня, поскольку он часто не заканчивался на элементе, который был в поле зрения перед поворотом. Поэтому я получил макет потока, который использует элемент фокуса (если установлен) для вычисления смещения содержимого. Я установил элемент в willAnimateRotationToInterfaceOrientation и очистил его в didRotateFromInterfaceOrientation. В IOS7 требуется настройка вставки, потому что представление Collection может располагаться под верхней панелью.

@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

Ответ 3

Для тех, кто использует iOS 8+, willRotateToInterfaceOrientation и didRotateFromInterfaceOrientation устарели.

Теперь вы должны использовать следующее:

/* 
This method is called when the view controller view 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
    }];
}

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

Ответ 4

Я думаю, что правильным решением является переопределить метод - (CGPoint) targetContentOffsetForProposedContentOffset: (CGPoint) предложилContentOffset в подклассе UICollectionViewFlowLayout

Из документов:

Во время обновления макета или при переходе между макетами коллекция рассматривает этот метод, чтобы дать вам возможность измените предлагаемое смещение контента для использования в конце анимации. Вы можете переопределить этот метод, если анимация или переход могут заставляйте предметы позиционировать таким образом, который не является оптимальным для вашего дизайн.

Ответ 5

Вот код в 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)
}

Ответ 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;
}

Довольно гладкий и менее хакерский.

Ответ 7

Я использую вариант fz. ответ (iOS 7 и 8):

Перед вращением:

  • Сохранять текущий видимый путь указателя
  • Создание моментального снимка коллекцииView
  • Поместите UIImageView с ним поверх представления коллекции

После вращения:

  • Прокрутите до сохраненного индекса
  • Снимите изображение.

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

Ответ 8

Эта работа похожа на обаяние:

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

Ответ 9

После поворота ориентации интерфейса UICollectionViewCell обычно перемещается в другую позицию, потому что мы не будем обновлять contentSize и contentOffset.

Таким образом, видимый UICollectionViewCell всегда не находится в ожидаемом положении.

Видимый UICollectionView, который мы ожидали, как показано ниже

Ориентация, которую мы ожидали

UICollectionView должен делегировать функцию [collectionView sizeForItemAtIndexPath] из 「UICollectionViewDelegateFlowLayout」.

И вы должны рассчитать размер элемента в этой функции.

Пользовательский UICollectionViewFlowLayout должен переопределить следующие функции.

  • -(void)prepareLayout

    . Установите itemSize, scrollDirection и другие.

  • -(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity

    . Вычислить номер страницы или рассчитать видимое смещение содержимого.

  • -(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset

    . Возвращение визуального содержимого.

  • -(CGSize)collectionViewContentSize

    . Верните общий размер содержимого коллекции.

Ваш viewController должен переопределить 「willRotateToInterfaceOrientation」 и в этой функции вы должны вызвать функцию [XXXCollectionVew.collectionViewLayout invalidateLayout];

Но 「willRotateToInterfaceOrientation」 устарела в iOS 9, или вы можете вызвать функцию [XXXCollectionVew.collectionViewLayout invalidateLayout] разным способом.

Вот пример: https://github.com/bcbod2002/CollectionViewRotationTest

Ответ 10

Чтобы отбросить решение 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

Ответ 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 также будет выполнять работу несколько иначе.

Ответ 12

Возможно, вам захочется скрыть коллекциюView во время ее (неправильной) анимации и показать вид замещающей ячейки ячейки, которая вращается правильно.

Для простой фотогалереи я нашел способ сделать это, что выглядит неплохо. См. Мой ответ здесь: Как повернуть UICollectionView, похожий на приложение для фотографий, и сохранить текущий центр в центре?

Ответ 13

Мой способ - использовать объект UICollectionViewFlowlayout.

Задайте расстояние между строками ojbect, если оно прокручивается горизонтально.

[flowLayout setMinimumLineSpacing:26.0f];

Установите интервал между интерметами, если он прокручивается вертикально.

[flowLayout setMinimumInteritemSpacing:0.0f];

Обратите внимание, что при повороте экрана оно ведет себя иначе. В моем случае, я прокручиваю его горизонтально, так что минимальное расстояние составляет 26.0f. Тогда это кажется ужасным, когда он вращается в ландшафтном направлении. Я должен проверить вращение и установить минимальное расстояние для этого направления 0.0f, чтобы сделать это правильно.

Что это! Простой.

Ответ 14

У меня была проблема с моим проектом, я использовал два разных макета для UICollectionView.

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

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

Затем проверьте его для каждой ориентации и используйте свою конфигурацию для каждой ориентации.

Ответ 15

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

Таким образом вы можете настроить смещение содержимого и размер вашей ячейки.

Ответ 16

Используйте <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);

    }

}

Ответ 17

У меня есть аналогичный случай, в котором я использую этот

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

Это настройка размеров ячеек в полноэкранном режиме (полный просмотр будет точным;)). Если вы этого не сделаете, может появиться много сообщений об ошибках, что размер ячейки больше, чем коллекция, и что поведение для этого не определено и bla bla bla.....

Эти методы не могут быть объединены в один подкласс коллекции или в представлении, содержащем viewview, но для моего текущего проекта это был логический путь.

Ответ 18

Что для меня значит эта работа:

  • Задайте размер моих ячеек из моего метода UICollectionViewDelegateFlowLayout

    func collectionView(collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize
    {
        return collectionView.bounds.size
    }
    
  • После этого я реализую 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, но вы получаете точку и легко "переводите"

Ответ 19

Ответ "просто щелкнуть" - это правильный подход и не требует дополнительного сглаживания с помощью наложений 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);
}

Ответ 20

Я решил эту проблему следующими шагами:

  • Вычислить прокрутку в текущий момент NSIndexPath
  • Отключить прокрутку и разбиение на страницы в UICollectionView
  • Применить новый макет потока к UICollectionView
  • Включить прокрутку и разбиение на страницы в UICollectionView
  • Прокрутить UICollectionView до текущего NSIndexPath

Вот шаблон кода, демонстрирующий Above Steps:

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

Надеюсь, это поможет.

Ответ 21

в 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 - это ширина просмотра коллекции, который был повернут.

Ответ 22

Возможно, вы захотите попробовать этот непроверенный код:

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