Photorama Deployment Target = 12.0
(For SafeAreaInsets)
Inside PhotosViewController.swift
…
override func viewDidLoad() {
super.viewDidLoad()collectionView.dataSource = photoDataSource collectionView.delegate = self // Add FlipBookFlowLayout to CollectionView collectionView.collectionViewLayout = FlipbookFlowLayout() store.fetchInterestingPhotos { (photosResult) -> Void in switch photosResult { case let .success(photos): print("Successfully found \(photos.count) photos.") self.photoDataSource.photos = photos case let .failure(error): print("Error fetching recent photos: \(error)") self.photoDataSource.photos.removeAll() } self.collectionView.reloadSections(IndexSet(integer: 0)) } }
…
FlipBookFlowLayout.swift
import UIKit
class FlipbookFlowLayout: UICollectionViewFlowLayout {
// Will Center the CollectionView's ImageView for Any Device private lazy var setup : Void = { Swift.print(#function) let collectionView = self.collectionView! let topSafeAreaInset = collectionView.safeAreaInsets.top self.scrollDirection = .vertical self.sectionInsetReference = .fromContentInset self.minimumLineSpacing = 20.0 self.minimumInteritemSpacing = 0.0 self.sectionInset = UIEdgeInsets(top: 20.0, left: 20.0, bottom: 20.0, right: 20.0) let width = collectionView.bounds.width - self.sectionInset.left - self.sectionInset.right // Remeber to Subtract NavigationController Bar if Present let height = collectionView.bounds.height - self.sectionInset.top - topSafeAreaInset - self.sectionInset.bottom self.itemSize = CGSize(width: width, height: height) Swift.print("CollectionView Bounds Size : \(self.collectionView!.bounds.size)") } () override func prepare() { // Call lazy closure (only happens once) _ = setup } // A Way to Snap to Images as Scrolling Occurs override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { var finalOffset = CGPoint() let height = self.sectionInset.top + self.itemSize.height switch velocity.y { case let y where y < 0 : finalOffset.y = height * ceil(proposedContentOffset.y / height) case let y where y == 0 : finalOffset.y = height * round(proposedContentOffset.y / height) default : finalOffset.y = height * floor(proposedContentOffset.y / height) } finalOffset.x = proposedContentOffset.x finalOffset.y -= self.collectionView!.safeAreaInsets.top return finalOffset } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let collectionView = self.collectionView, let allAttributes = super.layoutAttributesForElements(in: rect) else { return nil } // To Prevent Cache Error var modifiedAttributes : [UICollectionViewLayoutAttributes] = [] for attributes in allAttributes { // Size of Visible Portion of CollectionView. Here, it will be the size of the iPhone Screen (Ex : iPhone 8 ~ 375, 667) let collectionCenter = collectionView.bounds.size.height / 2 // Scrolling Downwards Increases Y-Offset. Scrolling Upwards Decreases Y-Offset let offset = collectionView.contentOffset.y // Center of Image Minus Y-Offset. Images Further Down Have Increased Normalized Center let normalizedCenter = attributes.center.y - offset /* Swift.print("Attributes : \(attributes)") Swift.print("CollectionCenter : \(collectionCenter)") Swift.print("Offset : \(offset)") Swift.print("Normalized Center : \(normalizedCenter)") Swift.print() */ let maxDistance = self.sectionInset.top + self.itemSize.height let distanceFromCenter = min(collectionCenter - normalizedCenter, maxDistance) // Ratio will be a value between 0 and 1. View further from center will usually decrease to a 0 ratio let ratio = (maxDistance - abs(distanceFromCenter)) / maxDistance // As Scrolling is Occurring, Will Adjust Alpha of Outgoing/Incoming Image let alpha = ratio // Angle to Adjust Outgoing Image let angleToSet = distanceFromCenter / (collectionView.bounds.height / 2) // To Prevent Cache Error let modified = attributes.copy() as! UICollectionViewLayoutAttributes modified.alpha = alpha // For the Outgoing Image, Rotate Along Y-Axix. Creates a Vertical Page Flipping Animation if (modified.frame.minY - collectionView.safeAreaInsets.top) <= collectionView.contentOffset.y { // Enlarges Bottom of Image As it is Outgoing modified.transform3D.m34 = 1 / 500 modified.transform3D = CATransform3DRotate(modified.transform3D, -angleToSet, 1, 0, 0) } modifiedAttributes.append(modified) } return modifiedAttributes }
}