Yalantis: iOS, Android And Web App Development Company

How We Built Tinder-Like Koloda Animation in Swift

Sometimes I think that Tinder’s mission in this world isn’t as much about helping people meet each other as it is about setting up new design trends. Then, we can definitely say that Tinder has already accomplished its mission, and can rest in peace until a new Tinder appears.

Tinder’s swipe right to like and left to pass isn’t only popular among dating app developers. Shopping apps, like Fancy, are following suit with similar swipe-to-like app formats. They are picking up this trend because quick card-based interactions really work. Items on a card grab users’ attention and urge them to take an action, thus increasing user engagement.

There are other examples of apps of various categories that use Tinder’s swipe theory: Jobr, an app for ... you guessed it – jobs and networking, real estate app Uptop, even Chrome for iOS which uses cards to manage bookmarks.

koloda animation

We featured card layouts and swipe-based navigation in our article about this year’s design trends. A bit later, our designer Dmitry Goncharov created an animation that follows Tinder’s trend, and he actually did it on purpose. The swipe-to-like interface is something people want to be part of.

We called our Tinder-style card-based animation Koloda which is a Ukrainian word for deck (of cards), and it sounds like fun to us. The component can be used in different local event apps, and even in Tinder if it adds a possibility to choose dating places. The concept created by Dmitriy was implemented by Eugene Andreyev, our iOS developer. Check it out on GitHub.

How we built Koloda animation

by Eugene Andreyev

Tinder’s swipe-to-like interface has been borrowed by various apps, so there are a few ready-made mobile libraries out there that an app developer can use. At first, I decided to look at MDCSwipeToChoose and TinderSimpleSwipeCards but as it turned out, these solutions weren’t perfect for my particular case.

I wanted the animation to be as simple and convenient as the data source driven views like UITableView. Therefore, I created a custom component for the animation. It consists of the three main parts:

  1. DraggableCardView – a card which displays content.
  2. OverlayView – a dynamic view which changes depending on where a user drags a card (to the left or to the right).
  3. KolodaView – a view that controls loading and interactions between cards.

Koloda Swipe to like tinder interface

DraggableCardView implementation

As I already mentioned, DraggableCardView is a card that displays content. There are many tutorials on the internet that explain how to animate cards in the Tinder style. I chose one of these solutions, looked at it, changed a few things, and here I am with my DraggableCardView implemented with the help of UIPanGestureRecognizer and CGAffineTransform. See the coding part below:

func panGestureRecognized(gestureRecognizer: UIPanGestureRecognizer) {
       xDistanceFromCenter = gestureRecognizer.translationInView(self).x
       yDistanceFromCenter = gestureRecognizer.translationInView(self).y

       let touchLocation = gestureRecognizer.locationInView(self)
       switch gestureRecognizer.state {
       case .Began:
           originalLocation = center

           animationDirection = touchLocation.y >= frame.size.height / 2 ? -1.0 : 1.0      
           layer.shouldRasterize = true
           break

       case .Changed:

           let rotationStrength = min(xDistanceFromCenter! / self.frame.size.width, rotationMax)
           let rotationAngle = animationDirection! * defaultRotationAngle * rotationStrength
           let scaleStrength = 1 - ((1 - scaleMin) * fabs(rotationStrength))
           let scale = max(scaleStrength, scaleMin)
           
           layer.rasterizationScale = scale * UIScreen.mainScreen().scale
 
           let transform = CGAffineTransformMakeRotation(rotationAngle)
           let scaleTransform = CGAffineTransformScale(transform, scale, scale)

           self.transform = scaleTransform
           center = CGPoint(x: originalLocation!.x + xDistanceFromCenter!, y: originalLocation!.y + yDistanceFromCenter!)
           
           updateOverlayWithFinishPercent(xDistanceFromCenter! / frame.size.width)
           //100% - for proportion
           delegate?.cardDraggedWithFinishPercent(self, percent: min(fabs(xDistanceFromCenter! * 100 / frame.size.width), 100))
           
           break
       case .Ended:
           swipeMadeAction()
           
           layer.shouldRasterize = false
       default :
           break
       }
   }

When a user starts dragging a top card, it’s turning and becoming shorter all the way until it reaches an action margin (go or pass an event), and after that it moves away from the screen. The distance to the action margin is represented in percent (100%). While the top card is being dragged, the card below is reacting too – it’s either expanding or contracting. In other words, the animation of an upper and a lower card stops simultaneously.

The overlay gets updated with every move. It changes transparency in the process of animation ( 5% –  hardly seen, 100% – clearly seen).

In order to avoid a card’s edges becoming sharp during movement I used shouldRasterize layer option.

What’s more, I had to consider reset situation which happens once a card fails to reach the action margin (ending point) and comes back to the initial state. I used Facebook Pop framework for this situation, and also for the “undo” action. If you remember, this framework drives animations and transitions in Paper app. It supports dynamic bounce animations and allows to build realistic interactions based on physics with just a few lines of code.

OverlayView implementation

OverlayView is a view that is added on top of a card during animation. It has only one variable called overlayState with two options: when a user drags a card to the left, the overlayState adds a red hue to the card, and when a card is moved to the right, the variable uses the other option to make the UI become green.

To implement custom actions for the overlay, we should inherit from OverlayView, and reload the operation didSet in the overlayState:

public enum OverlayMode{
   case None
   case Left
   case Right
}


public class OverlayView: UIView {
      public var overlayState:OverlayMode = OverlayMode.None
}

class ExampleOverlayView: OverlayView {
override var overlayState:OverlayMode  {
       didSet {
           switch overlayState {
           case .Left :
               overlayImageView.image = UIImage(named: overlayLeftImageName)
           case .Right :
               overlayImageView.image = UIImage(named: overlayRightImageName)
           default:
               overlayImageView.image = nil
           }          

       }

   }

}

KolodaView implementation

The KolodaView class does card loading and card management job. You can either implement it in the code or in the Interface Builder. Then, you should specify a datasource and add a delegate (optional). After that, you should implement the following methods of the KolodaViewDataSource protocol in the datasource-class:

    func kolodaNumberOfCards(koloda: KolodaView) -> UInt
    func kolodaViewForCardAtIndex(koloda: KolodaView, index: UInt) -> UIView
    func kolodaViewForCardOverlayAtIndex(koloda: KolodaView, index: UInt) -> OverlayView?

Regarding the callbacks, we get them through the delegate’s methods.

And...Geometry

Remember our story about developing the Guillotine menu animation for Android where Dmytro Denysenko, our Android developer, had to resort to high school Math course to build a custom interpolator? Geometry also helped me in my iOS development endeavours!

The most interesting thing in the Tinder-like animation is movement of lower cards while a user is dragging an upper card. I wanted to make the Koloda animation flexible, so that I could easily specify the number of cards I want to display on the screen. So I took a piece of paper and started my calculations.

How we develop Koloda Tinder-like card view animation

KolodaView had to display a correct number of cards below the top card, and make them occupy the right positions when the animation starts. To make it possible, I had to calculate frames for all the cards by adding the corresponding indexes to each element. For example, the first card has an [i] index, the second one would have a [i+1] index, the third – [i+2], and so on.

You can see the calculations of the original frame and the size of the first card below:

developing Tinder cardsAnd in the code:

private func frameForCardAtIndex(index: UInt) -> CGRect {
       let bottomOffset:CGFloat = 0
       let topOffset = backgroundCardsTopMargin * CGFloat(self.countOfVisibleCards - 1)
       let xOffset = backgroundCardsLeftMargin * CGFloat(index)
       let scalePercent = backgroundCardsScalePercent
       let width = CGRectGetWidth(self.frame) * pow(scalePercent, CGFloat(index))
       let height = (CGRectGetHeight(self.frame) - bottomOffset - topOffset) * pow(scalePercent, CGFloat(index))
       let multiplier: CGFloat = index > 0 ? 1.0 : 0.0
       let previousCardFrame = index > 0 ? frameForCardAtIndex(max(index - 1, 0)) : CGRectZero
       let yOffset = (CGRectGetHeight(previousCardFrame) - height + previousCardFrame.origin.y + backgroundCardsTopMargin) * multiplier
       let frame = CGRect(x: xOffset, y: yOffset, width: width, height: height)     

       return frame
   }

Now, since we know the indexes, card frames, and also a percent at which the animation ends (from the DraggableCardView), we can easily find out where the cards below will go once an upper card is swiped. After than we can implement PercentDrivenAnimation.

As a result, I achieved an easy to use component with an interesting name Koloda. Any developer can customize it by setting their content and overlay. In the future, I’d like to make it possible to customize frames’ calculations and animations so that any developer can make their own unique component.

Read also our article Koloda Tinder-like animation Version 2 where we improved funcationality of existing animation.

Check out KolodaView animaton on GitHub

See also:  Boboarding: open source onboarding constructor

 

 

 

Insights

How Much Does It Cost to Develop a Dating App Like Tinder?

Insights

How to Get the First 5 Thousand Users for Your Dating App

Tech

Koloda Tinder-Like Animation Version 2. Prototyping in Pixate and Development in Swift

Design

Eat. Drink. Track. How We Created Eat Fit iOS Animation Inspired by Google Fit

Design

UIDynamics, UIKit or OpenGL? 3 Types of iOS Animations for the Star Wars

Excited to create something outstanding?

We share the same interests.

Let's team up!