Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cards Swipe Direction #2

Open
Gantaios opened this issue Nov 7, 2017 · 7 comments
Open

Cards Swipe Direction #2

Gantaios opened this issue Nov 7, 2017 · 7 comments

Comments

@Gantaios
Copy link

Gantaios commented Nov 7, 2017

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.

@filletofish
Copy link
Owner

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.

@Viscmad
Copy link

Viscmad commented Nov 10, 2017

I have the same request. 👍

UPDATE : Looked into the code and did it myself.... https://pastebin.com/KjiYipEu
Cheers!

@filletofish
Copy link
Owner

@Viscmad Hey! That's nice! Do you want to form it in separate Pull Request?

@Viscmad
Copy link

Viscmad commented Nov 13, 2017

@filletofish Done 👍 :D

@bimawa
Copy link

bimawa commented Dec 23, 2018

guys, how can I do for direction left to right? :)

@HappyIosDeveloper
Copy link

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?

@HappyIosDeveloper
Copy link

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
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants