         
         return attr
     }
+    
+    /**
+     Updates the attributes.
+     Here manipulate the zIndex of the cards here, calculate the positions and do the animations.
+     - parameter attributes: The attributes we're updating.
+     */
+    fileprivate func updateCellAttributes(_ attributes: UICollectionViewLayoutAttributes) {
+        let minY = collectionView!.bounds.minY + collectionView!.contentInset.top
+        let maxY = attributes.frame.origin.y
+        
+        let finalY = max(minY, maxY)
+        var origin = attributes.frame.origin
+        let deltaY = (finalY - origin.y) / attributes.frame.height
+        
+        if let itemTransform = firstItemTransform {
+            let scale = 1 - deltaY * itemTransform
+            attributes.transform = CGAffineTransform(scaleX: scale, y: scale)
+            // TODO: add card stack effect (like Shazam)
+        }
+        origin.y = finalY
+        attributes.frame = CGRect(origin: origin, size: attributes.frame.size)
+        attributes.zIndex = attributes.indexPath.row
+    }
 }

        return items as? [UICollectionViewLayoutAttributes]
    }
    
    /**
     Updates the attributes.
     Here manipulate the zIndex of the cards here, calculate the positions and do the animations.
     - parameter attributes: The attributes we're updating.
    */
    func updateCellAttributes(_ attributes: UICollectionViewLayoutAttributes) {
        let minY = collectionView!.bounds.minY + collectionView!.contentInset.top
        let maxY = attributes.frame.origin.y
        
        let finalY = max(minY, maxY)
        var origin = attributes.frame.origin
        let deltaY = (finalY - origin.y) / attributes.frame.height
        
        if let itemTransform = firstItemTransform {
            let scale = 1 - deltaY * itemTransform
            attributes.transform = CGAffineTransform(scaleX: scale, y: scale)
            // TODO: add card stack effect (like Shazam)
        }
        origin.y = finalY
        attributes.frame = CGRect(origin: origin, size: attributes.frame.size)
        attributes.zIndex = attributes.indexPath.row
    }
    
    // We invalidate the layout when a "bounds change" happens, for example when we scale the top cell. This forces a layout update on the flowlayout.
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
    
    // Cell paging
    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        
        // If the property `isPagingEnabled` is set to false, we don't enable paging and thus return the current contentoffset.
        guard isPagingEnabled else {

        return CGPoint(x: proposedContentOffset.x, y: newVerticalOffset)
    }
    
    override internal func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {

        // make sure the zIndex of the next card is higher than the one we're swiping away.
        let nextIndexPath = IndexPath(row: itemIndexPath.row + 1, section: itemIndexPath.section)
