Как повернуть UICollectionView, похожий на приложение для фотографий, и сохранить текущий вид по центру?

У меня есть вид фотогалереи, который используетUICollectionView сUICollectionViewFlowLayout, в нем естьpagingEnabled и прокручивает горизонтально, показывая только один вид за раз.

Прекрасно работает, пока я не попробую повернуть его ...

Когда я поворачиваю устройство, вwillRotateToInterfaceOrientation:duration: Я обновляюcollectionView.contentOffset поэтому он остается на правильном элементе, и я изменяю размер currentCell, чтобы он анимировался в новые измерения.Проблема в анимации между двумя состояниями, анимация «предыдущей»из верхнего левого угла И бросает в глаза другие клетки. Что я делаю не так, что анимированный вид с экрана - это FUBAR?

Вот как это выглядит в действии:

http://www.smugmug.com/gallery/n-3F9kD/i-BwzRzRf/A (игнорируйте изменчивое видео, это вина Quicktime: p)

Вот мойwillAnimateRotationToInterfaceOrientation:duration:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

// Update the flowLayout's size to the new orientation's size
UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
    flow.itemSize = CGSizeMake(self.collectionView.frame.size.width, self.collectionView.frame.size.height);
} else {
    flow.itemSize = CGSizeMake(self.collectionView.frame.size.width, self.collectionView.frame.size.height);
}
self.collectionView.collectionViewLayout = flow;
[self.collectionView.collectionViewLayout invalidateLayout];

// Get the currently visible cell
PreviewCellView *currentCell = (PreviewCellView*)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:_currentIndex inSection:0]];

// Resize the currently index to the new flow's itemSize
CGRect frame = currentCell.frame;
frame.size = flow.itemSize;
currentCell.frame = frame;

// Keep the collection view centered by updating the content offset
CGPoint newContentOffset = CGPointMake(_currentIndex * frame.size.width, 0);
self.collectionView.contentOffset = newContentOffset;
}

Насколько мне известно, я не могу найти ни одного примера кода, который бы иллюстрировал, как сделать представление коллекции фотографий в стиле «фотогалерея», которое вращается изящно.

Ответы на вопрос(3)

-(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];
    }];
}
 LShi19 мар. 2018 г., 11:37
Решает ли это проблему сброса, о которой упоминалось op?
Решение Вопроса

пока, по крайней мере, не нашел этот «косметический обходной путь»:

Добавьте полноэкранный UIImageView с текущим изображением (и установите правильные ограничения автоматического макета) поверх collectionView во время вращения. Вот так:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration: (NSTimeInterval)duration 
{

[self.collectionView.collectionViewLayout invalidateLayout];

    // show a UIImageView with the current image on top of the collectionView 
    // to cover the ugly animation
    self.imageViewOnTopOfCollectionView.image = [self imageForItemAtIndexPath:self.currentIndexPath];
    self.imageViewOnTopOfCollectionView.hidden = NO;

    // show a centered, very large 'fakeBackground' view on top of
    // the UICollectionView, but below the UIImageView
    self.fakeBackground.hidden = NO;
}

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    // ... set correct contentOffset

    // hide the fake views again
    self.imageViewOnTopOfCollectionView.hidden = YES;
    self.fakeBackground.hidden = YES;
}

Большой «fakeBackground» был бы дополнительным улучшением, чтобы не допустить, чтобы части уродливой анимации представления коллекции были видны за пределами этого кадра imageViews во время его вращения. Например. увеличенный (больше, чем границы представления во всех измерениях) UIView с тем же цветом фона, что и collectionView, с z-индексом только между collectionView и imageView.

 Ben Williams30 мар. 2015 г., 23:50
Альтернатива для fakeBackground - просто установить backgroundColor для imageViewOnTopOfCollectionView в черный (или другой сплошной цвет).
 groomsy15 нояб. 2013 г., 20:07
Единственное, что я бы добавил к этому: в методе willRotate рассчитайте текущую позицию прокрутки. затем используйте эту позицию в didRotate. Мне понадобилось несколько минут, чтобы понять эту часть после просмотра вашего кода, но до меня дошло. В противном случае, элегантное решение неэлементной проблемы.
 Shizam25 сент. 2013 г., 19:52
Я также остановился на этом решении, но вселял надежду, что есть элегантный способ сделать это, просто используя сам UICollectionView, хотя, похоже, это не произойдет :)
 Goodsquirrel22 мая 2015 г., 21:08
@ alku83: я не думаю, что это решит проблему. ImageViewOnTopOfCollectionView просто недостаточно велик, чтобы полностью скрыть представленные ниже виды во время вращения. Изменение цвета фона не увеличивает вид. (FakeBackground необходим не только для изображений, которые меньше, чем экран, но также и для полноэкранных изображений.)

отличному ответу rrel, вот как я реализовал его, используя текущие API iOS8 и Swift:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator);

    // show the dummy imageView
    self.imageViewOnTopOfCollectionView.image = self.imageForItemAtIndex(self.currentIndex)
    self.imageViewOnTopOfCollectionView.hidden = false;

    coordinator.animateAlongsideTransition({ (context) -> Void in
        // update the dummy imageView's frame
        var frame:CGRect = self.imageViewOnTopOfCollectionView.frame;
        frame.size = size;
        self.imageViewOnTopOfCollectionView.frame = frame;

        // update the flow's item size
        if let flow = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            flow.itemSize = size;
        }

        // scroll to the current index
        self.scrollToItem(self.currentIndex);
        }, completion: { (context) -> Void in
            // remove the dummy imageView
            self.imageViewOnTopOfCollectionView.hidden = true;
    });
}

Ваш ответ на вопрос