CardsLayout
CardsLayout copied to clipboard
Cards Swipe Direction
Hi thanks for your excellent repository i just want to have this thing how to change the swipe direction i want the cards to swipe up and down.
Hi @Gantaios! Thank you for your notice.
In order to have direction of the layout vertical, not from right to left, one have to rewrite the class to use contentOffset.y.
Implementing this feature is on my roadmap. I will try to add it as soon as possible.
I have the same request. 👍
UPDATE : Looked into the code and did it myself.... https://pastebin.com/KjiYipEu Cheers!
@Viscmad Hey! That's nice! Do you want to form it in separate Pull Request?
@filletofish Done 👍 :D
guys, how can I do for direction left to right? :)
I tested the @filletofish answer but the scroll has weird issues & it's not perfect. is there any other solution to change scroll direction to vertical?
Finally I came up with this:
import UIKit
open class CardsCollectionViewLayout: UICollectionViewLayout {
// MARK: - Layout configuration
public var itemSize: CGSize = CGSize(width: 200, height: 100) {
didSet{
invalidateLayout()
}
}
public var spacing: CGFloat = 10.0 {
didSet{
invalidateLayout()
}
}
public var maximumVisibleItems: Int = 3 {
didSet{
invalidateLayout()
}
}
// MARK: UICollectionViewLayout
override open var collectionView: UICollectionView {
return super.collectionView!
}
override open var collectionViewContentSize: CGSize {
let itemsCount = CGFloat(collectionView.numberOfItems(inSection: 0))
return CGSize(width: collectionView.bounds.width * itemsCount, height: collectionView.bounds.height * itemsCount)
}
override open func prepare() {
super.prepare()
assert(collectionView.numberOfSections == 1, "Multiple sections aren't supported!")
}
override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let totalItemsCount = collectionView.numberOfItems(inSection: 0)
let minVisibleIndex = max(Int(collectionView.contentOffset.y) / Int(collectionView.bounds.height), 0)
let maxVisibleIndex = min(minVisibleIndex + maximumVisibleItems, totalItemsCount)
let contentCenterX = collectionView.contentOffset.x + (collectionView.bounds.width / 2.0)
let deltaOffset = Int(collectionView.contentOffset.y) % Int(collectionView.bounds.height)
let percentageDeltaOffset = CGFloat(deltaOffset) / collectionView.bounds.height
let visibleIndices = minVisibleIndex..<maxVisibleIndex
let attributes: [UICollectionViewLayoutAttributes] = visibleIndices.map { index in
let indexPath = IndexPath(item: index, section: 0)
return computeLayoutAttributesForItem(indexPath: indexPath, minVisibleIndex: minVisibleIndex, contentCenterX: contentCenterX, deltaOffset: CGFloat(deltaOffset), percentageDeltaOffset: percentageDeltaOffset)
}
return attributes
}
override open func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let contentCenterX = collectionView.contentOffset.x + (collectionView.bounds.width / 2.0)
let minVisibleIndex = Int(collectionView.contentOffset.x) / Int(collectionView.bounds.width)
let deltaOffset = Int(collectionView.contentOffset.y) % Int(collectionView.bounds.height)
let percentageDeltaOffset = CGFloat(deltaOffset) / collectionView.bounds.height
return computeLayoutAttributesForItem(indexPath: indexPath, minVisibleIndex: minVisibleIndex, contentCenterX: contentCenterX, deltaOffset: CGFloat(deltaOffset), percentageDeltaOffset: percentageDeltaOffset)
}
override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
// MARK: - Layout computations fileprivate extension CardsCollectionViewLayout {
private func scale(at index: Int) -> CGFloat {
let translatedCoefficient = CGFloat(index) - CGFloat(self.maximumVisibleItems) / 2
return CGFloat(pow(0.95, translatedCoefficient))
}
private func transform(atCurrentVisibleIndex visibleIndex: Int, percentageOffset: CGFloat) -> CGAffineTransform {
var rawScale = visibleIndex < maximumVisibleItems ? scale(at: visibleIndex) : 1.0
if visibleIndex != 0 {
let previousScale = scale(at: visibleIndex - 1)
let delta = (previousScale - rawScale) * percentageOffset
rawScale += delta
}
return CGAffineTransform(scaleX: rawScale, y: rawScale)
}
func computeLayoutAttributesForItem(indexPath: IndexPath, minVisibleIndex: Int, contentCenterX: CGFloat, deltaOffset: CGFloat, percentageDeltaOffset: CGFloat) -> UICollectionViewLayoutAttributes {
let attributes = UICollectionViewLayoutAttributes(forCellWith:indexPath)
let visibleIndex = indexPath.row - minVisibleIndex
//Using this to fill up screen with card with fixed % of margin
attributes.size = CGSize(width: (collectionView.bounds.width - ((collectionView.bounds.width * 2)/100)), height: (collectionView.bounds.height - ((collectionView.bounds.height * 4)/100)))
let midY = self.collectionView.bounds.midY
attributes.center = CGPoint(x: contentCenterX , y: midY + spacing * CGFloat(visibleIndex)) // MARK: this x spacing value is the key to home page center cell xposition
attributes.zIndex = maximumVisibleItems - visibleIndex
attributes.transform = transform(atCurrentVisibleIndex: visibleIndex, percentageOffset: percentageDeltaOffset)
switch visibleIndex {
case 0:
attributes.center.y -= deltaOffset
case 1..<maximumVisibleItems:
attributes.center.y -= spacing * percentageDeltaOffset
if visibleIndex == maximumVisibleItems - 1 {
attributes.alpha = percentageDeltaOffset
}
default:
attributes.alpha = 0
}
return attributes
}
}