Gold Challenge (simple way)

/* -------------------------------------------- my add for the Gold Challenge -------------------------------------------- */

/— used Xcode vers. 7.3 and Swift vers. 2.2 —/

/* based on alpha009’s solution and on https://www.raywenderlich.com/94565/how-to-create-an-ios-book-open-animation-part-1 */

/* The only problem is that if I click on odd numbered photos (those staying on the left hand side of the book’s spine) I always end up on the first photo, while if I click on even numbered photos (those staying on the right hand side of the book’s spine) I end up on the correct photo. If someone will be able to solve this issue, then he/she is really great! */

import UIKit

class Layout: UICollectionViewFlowLayout {

// var landscape: Bool = true
// var portrait: Bool = true

private var photoWidth: CGFloat = 300
private var photoHeight: CGFloat = 300
private var numberOfPhotos = 0
private var currentPhoto = 0

override func prepareLayout() {
    
    super.prepareLayout()
    collectionView?.decelerationRate = UIScrollViewDecelerationRateFast
    numberOfPhotos = collectionView!.numberOfItemsInSection(0)
    print("Number of photos: \(numberOfPhotos)")
    collectionView?.pagingEnabled = true
    
    /* NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(rotated), name: UIDeviceOrientationDidChangeNotification, object: nil) */
}

/*
func rotated() {
    switch UIDevice.currentDevice().orientation {
    case UIDeviceOrientation.LandscapeLeft, UIDeviceOrientation.LandscapeRight:
        landscape = true
        portrait = false
    default:
        portrait = true
        landscape = false
    }
}
*/

override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
    return true
}

override func collectionViewContentSize() -> CGSize {
    return CGSizeMake(CGFloat(numberOfPhotos / 2 + 1) * collectionView!.bounds.width, collectionView!.bounds.height - (collectionView?.contentInset.top)!)
}

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    
    var array: [UICollectionViewLayoutAttributes] = []
    
    if numberOfPhotos == 0 {
        return array
    }
    
    for i in 0 ... max(0, numberOfPhotos - 1) {
    //for i in 0 ... (numberOfPhotos - 1) {
        
        let indexPath = NSIndexPath(forItem: i, inSection: 0)
        
        if let attributes = layoutAttributesForItemAtIndexPath(indexPath) {
            array.append(attributes)
        } else {
            // print("Failed to create attributes")
        }
    }
    return array
}

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) ->UICollectionViewLayoutAttributes? {
    
    let layoutAttributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
    
    let frame = getFrame(collectionView!)
    
    /*
    rotated()
    
    var frame: CGRect!
    
    if portrait == true {
        frame = getFrameForPortrait(collectionView!)
    }
    else if landscape == true {
        frame = getFrameForLandscape(collectionView!)
    }
    */
    
    layoutAttributes.frame = frame
    
    let ratio = getRatio(collectionView!, indexPath: indexPath)
    
    let rotation = getRotation(indexPath, ratio: min(max(ratio, -1), 1))
    
    layoutAttributes.transform3D = rotation
    
    layoutAttributes.zIndex = numberOfPhotos - indexPath.item

    return layoutAttributes
}

// MARK: - Attribute Logic Helpers

func getFrame(collectionView: UICollectionView) -> CGRect {
    var frame = CGRect()
    
    photoWidth = collectionView.bounds.width / 2
    photoHeight = photoWidth
    
    frame.origin.x = collectionView.bounds.width / 2 - photoWidth / 2 + collectionView.contentOffset.x
    frame.origin.y = (collectionViewContentSize().height - photoHeight) / 2
    
    frame.size.width = photoWidth
    frame.size.height = photoHeight
    
    return frame
}

/*
func getFrameForPortrait(collectionView: UICollectionView) -> CGRect {
    var frame = CGRect()
    
    photoWidth = collectionView.bounds.width / 2
    photoHeight = photoWidth
    
    frame.origin.x = collectionView.bounds.width / 2 - photoWidth / 2 + collectionView.contentOffset.x
    frame.origin.y = (collectionViewContentSize().height - photoHeight) / 2
    
    frame.size.width = photoWidth
    frame.size.height = photoHeight
    
    return frame
}

func getFrameForLandscape(collectionView: UICollectionView) -> CGRect {
    var frame = CGRect()
    
    photoWidth = collectionView.bounds.width / 2
    // photoWidth = collectionView.bounds.height - (collectionView.contentInset.top)
    photoHeight = photoWidth
    
    frame.origin.x = collectionView.bounds.width / 2 - (photoWidth / 2) + collectionView.contentOffset.x
    frame.origin.y = (collectionViewContentSize().height - photoHeight) / 2
    
    frame.size.width = photoWidth
    frame.size.height = photoHeight
    
    return frame
}
*/

func getRatio(collectionView: UICollectionView, indexPath: NSIndexPath) -> CGFloat {
    
    let page = CGFloat(indexPath.item - indexPath.item % 2) * 0.5
    
    print("page xxx = \(page), indexPath.item = \(indexPath.item), indexPath.item % 2 = \(indexPath.item % 2)")
    
    var ratio: CGFloat = 0.5 + page - (collectionView.contentOffset.x / collectionView.bounds.width)
    
    if ratio > 0.5 {
        ratio = 0.5 + 0.1 * (ratio - 0.5)
    }
    else if ratio < -0.5 {
        ratio = -0.5 + 0.1 * (ratio + 0.5)
    }
    // currentPhoto = Int(collectionView.contentOffset.x / photoWidth)
    
    return ratio
}

func getAngle(indexPath: NSIndexPath, ratio: CGFloat) -> CGFloat {
    
    var angle: CGFloat = 0
    
    if indexPath.item % 2 == 0 {
        angle = (1-ratio) * CGFloat(-M_PI_2)
    }
    else {
        angle = (1 + ratio) * CGFloat(M_PI_2)
    }
    
    angle += CGFloat(indexPath.row % 2) / 1000

    return angle
}

func makePerspectiveTransform() -> CATransform3D {
    var transform = CATransform3DIdentity
    transform.m34 = 1.0 / -2000
    return transform
}

func getRotation(indexPath: NSIndexPath, ratio: CGFloat) -> CATransform3D {
    var transform = makePerspectiveTransform()
    let angle = getAngle(indexPath, ratio: ratio)
    transform = CATransform3DRotate(transform, angle, 0, 1, 0)
    return transform
}

}

import UIKit

class PhotoCollectionViewCell: UICollectionViewCell {

/*----------................... my add for the Gold Challenge ----------*/

override func applyLayoutAttributes(layoutAttributes: UICollectionViewLayoutAttributes) {
    super.applyLayoutAttributes(layoutAttributes)
    
    if layoutAttributes.indexPath.item % 2 == 0 {
        layer.anchorPoint = CGPointMake(0, 0.5)
    }
    else {
        layer.anchorPoint = CGPointMake(1, 0.5)
    }
}

}