Как повернуть 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 size to the new orientation 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 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;
}
Насколько мне известно, я не могу найти какой-либо образец кода в любом месте, что иллюстрирует, как сделать "коллекцию" стиля коллекции "фото галерея", которая грациозно вращается.
Ответы
Ответ 1
Я долгое время боролся с этим, пока я, по крайней мере, не нашел это "косметическое обходное решение":
Добавьте полный экран UIImageView с текущим изображением (и установите правильные ограничения макета) в верхней части коллекцииView во время вращения. Например:
-(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" станет дополнительным улучшением, чтобы предотвратить появление части анимации уродливого коллекционного просмотра вне этого кадра изображения. Пока он вращается. Например. (больше, чем границы обзора во всех измерениях) UIView с тем же цветом фона, что и CollectionView, с z-индексом только между collectionView и imageView.
Ответ 2
Эта работа похожа на обаяние:
-(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];
}];
}
Ответ 3
Добавляя к @Goodsquirrel отличный ответ, вот как я его реализовал с использованием текущего 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 frame
var frame:CGRect = self.imageViewOnTopOfCollectionView.frame;
frame.size = size;
self.imageViewOnTopOfCollectionView.frame = frame;
// update the flow 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;
});
}