Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rotate a UICollectionView similar to the photos app and keep the current view centered?

I have a photo gallery view that uses a UICollectionView with a UICollectionViewFlowLayout, it has pagingEnabled and scrolls horizontally showing only one view at a time.

Works great till I try to rotate it...

When I rotate the device, in willRotateToInterfaceOrientation:duration: I update the collectionView.contentOffset so it stays on the correct item and I resize the currentCell so it animates into the new dimensions. The problem is in the animation between the two states, the 'previous' orientation animates from the upper left corner AND flings into the view other cells. What is it I'm doing wrong such that the view being animated off the screen is FUBAR?

Here is what it looks like in action:

http://www.smugmug.com/gallery/n-3F9kD/i-BwzRzRf/A (ignore the choppy video, thats Quicktime's fault :p)

Here is my 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;
}

As far as I'm aware I can't find any sample code anywhere that illustrates how to make a 'photo gallery' style collection view that rotates gracefully.

like image 562
Shizam Avatar asked Sep 09 '13 23:09

Shizam


People also ask

How do I fix the orientation of a picture?

Right-click the image and select Details to reveal a screen with metadata, including EXIF data, that you can adjust if the image supports it. Force a preferred orientation. Rotate the image, then save it. That process reconstructs the image along the requested dimensions.

How do I change the rotation of a picture?

Select the picture or shape. This will open the Shape Format or Picture Format ribbon. Select Rotate. Use any of the rotation commands in the list, like Flip Horizontal.

What is Auto Photo Orientation?

This means that most cameras store images' pixels exactly the same whether the camera is oriented in landscape or portrait mode. They just flip a bit to signal to the viewer whether to display the pixels as-is or to rotate them by 90 or 180 degrees when displaying the image.

Why are uploaded photos sideways?

Photos taken on smartphones, tablets and some cameras can look great on your device but appear upside down or sideways when uploaded to a post or page because the device stores the image's orientation in the EXIF metadata and not all software is able to read the metadata.


1 Answers

I struggled with this for quite a while, until I at least found this 'cosmetic workaround':

Add a full screen UIImageView with the current image (and correct auto layout constraints set) on top of the collectionView during rotation. Like so:

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

A large 'fakeBackground' would be an extra improvement to prevent parts of the ugly collection view animation being visible outside this imageViews frame while it rotates. E.g. an oversized (larger than the view's bounds in all dimensions) UIView with the same background color as the collectionView, with a z-Index just between the collectionView and the imageView.

like image 146
Goodsquirrel Avatar answered Nov 15 '22 23:11

Goodsquirrel