Search code examples
iosswiftsnapkitkoloda

Koloda - Animate shuffle effect on load


I am using Koloda to present a deck of playing cards that can be swiped through. I have this part working well.

When I initially load this deck of cards I would like each view / card to fly in separately and then show as being stacked. I would call this a shuffle or a deal effect (like when you deal cards). From what I can tell it appears Koloda does not allow for this. The animations I see are for showing the entire stack of views / frames after they are already stacked up. So in my example this would mean the entire deck. I also do not see a way to add views / cards 1 by 1 without causing a full reload.

Here is how I would like it work if I had 3 cards

Card 1 (bottom of deck flies in from left in animated fashion)

.2 second wait

Card 2 (2nd from bottom of deck / middle card flies in)

.2 second wait

Card 3 (top of deck flies in)

Proceed as normal Koloda View.

I have tried adding animations to my UIViews that get added as contentViews but it doesn't look right. My current guess is a custom animation using animateAppearanceWithCompletion but I have not had much luck. There is also a frameForCard method that might work?

I am using Snapkit in the project if that helps. I am targeting iOS 9+


Solution

  • I subclassed KolodaViewAnimator and overrode the initial loading animation

    override func animateAppearanceWithCompletion(_ completion: KolodaViewAnimator.AnimationCompletionBlock) {
    
        self.koloda?.alpha = 1.0
    
        // custom extension method to return my CardView
        let cards = self.koloda!.cards().reversed()
        for (index, card) in cards.enumerated() {
            let delay = Double(index) * 0.2
            card.display(delay: delay)
        }
    
        completion?(true)
    }
    

    Since I am targeting iOS 9+ I can use transforms in my init / setup phase of my custom view. Start off screen.

    self.mySubView?.transform = CGAffineTransform(translationX: self.frame.width * -2, y: 0)
    

    Call display() to trigger animation from the subclassed ViewAnimator

        func display(delay: TimeInterval) {
    
            UIView.animate(withDuration: 0.2, delay: delay, options: [], animations: {
    // could be a subview
                self.mySubView.transform = CGAffineTransform(translationX: 0, y: 0)
    
            }) { (_) in
    
            }
    
        }