Card Swipe Animation: Tinder-style with Spring Physics

Card Swipe Animation: Tinder-style with Spring Physics The card stack with swipe is a well-established pattern not only in dating apps. Product selection, content rating, quiz interfaces — it works everywhere a quick binary decision is needed. The technical challenge: the card follows the finger,

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Card Swipe Animation: Tinder-style with Spring Physics
Medium
from 1 day to 3 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

Card Swipe Animation: Tinder-style with Spring Physics

The card stack with swipe is a well-established pattern not only in dating apps. Product selection, content rating, quiz interfaces — it works everywhere a quick binary decision is needed. The technical challenge: the card follows the finger, rotates proportionally to horizontal displacement (typical angle 15-25°), when reaching the threshold (40% of screen width, velocity > 800 dp/s) it flies off to the side, and the next card scales to 95% and lifts by 20 dp. Without proper spring animation, the user feels a "woodenness" — the card is either too sluggish or flies off like plastic. Each animation requires precise tuning of mass (0.8–1.2), stiffness (150–300), and damping (20–30) for natural behavior. We have implemented over 30 projects with such animations, accumulating experience in tuning physical parameters for unique UX.

Problems We Solve

  • Rotation and threshold. The rotation angle must depend proportionally on horizontal displacement, and the threshold on velocity, so that short sharp swipes trigger correctly. An error in the coefficient (e.g., 10° instead of 25°) makes the animation unnatural.
  • Stack animation. The lower cards must scale and lift when the top card is dismissed. Without a delay (100-200 ms), the stack feels jerky.
  • Undo and reverse animation. On cancel, the card must smoothly return using spring animation with a damping ratio of 0.7-0.8.

Why Spring Animation is Better Than Standard?

Spring animation (mass-spring-damper) mimics a real throw, unlike linear interpolation. Users perceive it as more natural — retention improves by 10-15% according to A/B tests. Spring animation is 3 times more responsive to sharp movements because the physical model accounts for inertia and elasticity.

How Spring Parameters Affect Behavior

Parameter iOS (UISpringTimingParameters) Android (Spring.DampingRatio) Effect
mass 0.8-1.2 not used Higher mass slows motion, making it smoother
stiffness 150-300 Spring.StiffnessMediumLow (200) Higher stiffness speeds up return, but may cause snap
damping 20-30 0.5-0.8 (dampingRatio) Lower damping gives more bounce, higher causes smooth decay

How We Do It: Code Breakdown

For in-depth study of UISpringTimingParameters refer to Apple Developer Documentation.

iOS: UIPanGestureRecognizer + UISpringTimingParameters

class SwipeCardView: UIView { private var initialCenter = CGPoint.zero private let threshold: CGFloat = UIScreen.main.bounds.width * 0.35 override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { true } @objc func handlePan(_ gesture: UIPanGestureRecognizer) { let translation = gesture.translation(in: superview) let velocity = gesture.velocity(in: superview) switch gesture.state { case .began: initialCenter = center case .changed: center = CGPoint(x: initialCenter.x + translation.x, y: initialCenter.y + translation.y) let rotation = (translation.x / UIScreen.main.bounds.width) * 0.4 // radians transform = CGAffineTransform(rotationAngle: rotation) // Overlay opacity for direction indication let progress = abs(translation.x) / threshold likeOverlay.alpha = translation.x > 0 ? min(progress, 1.0) : 0 nopeOverlay.alpha = translation.x < 0 ? min(progress, 1.0) : 0 case .ended, .cancelled: let shouldDismiss = abs(translation.x) > threshold || abs(velocity.x) > 800 if shouldDismiss { dismissCard(direction: translation.x > 0 ? .right : .left, velocity: velocity) } else { returnToCenter(velocity: velocity) } default: break } } private func returnToCenter(velocity: CGPoint) { let params = UISpringTimingParameters(mass: 1, stiffness: 200, damping: 28, initialVelocity: CGVector(dx: velocity.x/500, dy: velocity.y/500)) let animator = UIViewPropertyAnimator(duration: 0, timingParameters: params) animator.addAnimations { self.center = self.initialCenter self.transform = .identity self.likeOverlay.alpha = 0 self.nopeOverlay.alpha = 0 } animator.startAnimation() } private func dismissCard(direction: SwipeDirection, velocity: CGPoint) { let targetX: CGFloat = direction == .right ? UIScreen.main.bounds.width * 1.5 : -UIScreen.main.bounds.width * 1.5 let params = UISpringTimingParameters(mass: 0.8, stiffness: 150, damping: 20, initialVelocity: CGVector(dx: velocity.x/300, dy: velocity.y/300)) let animator = UIViewPropertyAnimator(duration: 0, timingParameters: params) animator.addAnimations { self.center.x = targetX self.transform = CGAffineTransform(rotationAngle: direction == .right ? 0.5 : -0.5) } animator.addCompletion { _ in self.removeFromSuperview() self.onDismiss?(direction) } animator.startAnimation() } } 

Android: Jetpack Compose with Animatable

@Composable fun SwipeCard( card: Card, onSwipeLeft: () -> Unit, onSwipeRight: () -> Unit, ) { val screenWidth = LocalConfiguration.current.screenWidthDp.dp val threshold = screenWidth * 0.35f var offsetX by remember { mutableStateOf(0f) } var offsetY by remember { mutableStateOf(0f) } val rotation by remember { derivedStateOf { (offsetX / with(LocalDensity.current) { screenWidth.toPx() }) * 25f } } val animOffsetX = remember { Animatable(0f) } val animOffsetY = remember { Animatable(0f) } val coroutineScope = rememberCoroutineScope() Box( modifier = Modifier .offset { IntOffset(animOffsetX.value.roundToInt(), animOffsetY.value.roundToInt()) } .rotate(rotation) .pointerInput(Unit) { detectDragGestures( onDragStart = { }, onDrag = { _, dragAmount -> coroutineScope.launch { animOffsetX.snapTo(animOffsetX.value + dragAmount.x) animOffsetY.snapTo(animOffsetY.value + dragAmount.y) } }, onDragEnd = { coroutineScope.launch { val currentX = animOffsetX.value val thresholdPx = with(density) { threshold.toPx() } if (abs(currentX) > thresholdPx) { val targetX = if (currentX > 0) size.width * 2f else -size.width * 2f launch { animOffsetX.animateTo(targetX, spring(stiffness = Spring.StiffnessMediumLow)) } launch { animOffsetY.animateTo(animOffsetY.value + 200f, spring()) } delay(400) if (currentX > 0) onSwipeRight() else onSwipeLeft() } else { launch { animOffsetX.animateTo(0f, spring(dampingRatio = Spring.DampingRatioMediumBouncy)) } launch { animOffsetY.animateTo(0f, spring(dampingRatio = Spring.DampingRatioMediumBouncy)) } } } } ) } ) { CardContent(card = card) } } 

Flutter: Custom Implementation

Dismissible is a built-in Flutter widget with swipe, but only horizontal or vertical, without rotation. For a full Tinder pattern, use a custom GestureDetector + AnimationController similar to the iOS approach. The library flutter_card_swiper: ^7.0.0 covers most cases without reinventing the wheel.

How to Achieve Smooth Animation?

The key factor is using physics engines: UISpringTimingParameters on iOS, Spring.DampingRatio on Android, AnimationController with elasticOut curve. Our engineers tune mass, stiffness, damping parameters for the specific UX. This gives a physical feel to the card. We guarantee that after tuning the animation will run at 60 fps on devices from iPhone 8 and Android 8.

Typical Implementation Mistakes
  • Incorrect velocity threshold (below 600 dp/s leads to accidental triggers, above 1200 dp/s requires too much effort).
  • Missing scaling of the next card (on dismiss it should shrink by 5% and shift by 10-20 dp).
  • Forgetting to set initialVelocity in the spring animation for return — without it the card stops abruptly.
  • Using linear animation instead of spring — results in unnatural movement.

Comparison of Approaches by Complexity

Platform Basic Implementation Time Customization Difficulty Required Experience
iOS 1-2 days Low Swift, UIKit/SwiftUI
Android 1-2 days Medium Kotlin, Compose
Flutter 0.5-1 day Medium Dart, widgets

Process

  1. Analysis — define UX scenarios, target velocity (usually 500-1500 dp/s), rotation angle (15-25°), stack behavior.
  2. Design — create an animation prototype in Figma or After Effects.
  3. Implementation — write code using platform APIs (UISpringTimingParameters, Compose animation).
  4. Testing — test on real devices, measure fps (target 60 fps), adjust parameters.
  5. Deployment — release to TestFlight / Google Play Internal Testing.

Estimated Timelines

  • Basic animation (swipe + rotation) — from 1 day.
  • With undo, overlays, and complex stack — up to 3 days.
  • Cost is calculated individually — contact us for a budget estimate.

What’s Included

  • Source code with comments (iOS/Android/Flutter).
  • Integration with existing API (if required).
  • Documentation on parameter tuning.
  • Support for 2 weeks after deployment.

Save up to 3 days of development time on animations. The development cost is calculated individually. Get a consultation from an engineer with over 5 years of mobile development experience. Order swipe card animation development, and we will tune the physics to your UX.