Blog

Animated Quote Cards in Android: Building Swipeable Kotlin UI

Most card-swiping tutorials give you two buttons and call it done. The pattern that follows does something different: one card, one gesture, and a threshold that decides whether the next quote loads.

The version originally published on freeCodeCamp gets this right by stripping the UI to a single interaction point. The math behind the threshold is what separates a swipe that feels responsive from one that feels arbitrary. Here's how the touch listener, the position calculations and the snap-back behavior come together.

The two touch events that matter

Sliding a card only needs two of the touch events Android exposes. ACTION_MOVE fires while the user's finger is down and the card is being repositioned. ACTION_UP fires when the finger lifts, which is the moment the app decides what to do.

Other events, including ACTION_DOWN, aren't needed for this pattern. Skipping them keeps the listener readable and removes a class of accidental triggers.

The math behind the snap-back

The defining decision in this pattern is where to draw the threshold. The implementation defines the "average position" as the horizontal center of the card. If the user swipes left of center and crosses a minimum distance, the card is treated as accepted: it returns to its original position and the app loads the next quote.

The crucial detail is that the starting position of the card is calculated against the full screen width, not the card's own width. Without that, the threshold shifts depending on screen size and the snap-back behavior becomes inconsistent across devices.

How to apply the sliding logic

The implementation captures the starting X position once, before the touch events fire. On each ACTION_MOVE, the code compares the new X against the start. If the user is dragging left past the center, the card's translation X is updated to match the finger.

On ACTION_UP, the code checks the distance travelled. If it crosses the threshold, the card animates back to its rest position and the new quote is loaded. If not, the card animates back from wherever it currently is. Either way, the card visibly returns home before any content swap, which keeps the gesture from feeling laggy.

Why it matters

The pattern works because it commits to one direction. Forcing left-only swipe removes a class of edge cases the listener would otherwise need to handle, and it lets the loading state be modeled as a clean boolean: the gesture was accepted or it wasn't.

The trade-off is reachability. Right-handed users find left-swipe natural, but the pattern excludes users who rely on directional buttons or assistive navigation unless you mirror the behavior or attach the same action to a fallback control. For apps where accessibility compliance is a hard requirement, this is not optional—it needs to be in the initial spec.

Who wins: apps that want a contained, single-purpose gesture. Dating apps, flashcard tools, and quote browsers all benefit from the clarity of one action per direction.

What to watch: screen density. The raw X coordinates returned by the touch event are in pixels, which means thresholds calibrated on one device may feel too sensitive or too sluggish on another. Testing across at least three screen densities before shipping is the minimum.

Decision checklist

Before implementing, confirm each of these:

Check Reason
One direction only Simplifies threshold logic and reduces edge cases
Threshold relative to screen width Keeps behavior consistent across device sizes
Card returns home before content swap Prevents the "jumping" feel during load
Fallback control exists Accessibility and users who can't perform the gesture
Tested across screen densities Pixel-based math behaves differently on high-DPI displays
Loading state visible User needs feedback during quote fetch

Bottom line

One direction, two touch events, threshold against full screen width. Get those three right, and the rest of the gesture code writes itself.

Key takeaways

  • ACTION_MOVE and ACTION_UP are the only touch events needed for a left-only swipe card.
  • Calculate card position relative to full screen width, not card width, for consistent threshold behavior.
  • The card always animates back to its rest position before content loads—no matter the swipe distance.
  • Accessibility requires a fallback control; don't ship the gesture alone.
  • Test across multiple screen densities; pixel-based coordinates behave differently at various DPIs.

Frequently asked questions

Which Android touch events are used for a swipeable card?

The pattern relies on ACTION_MOVE for the slide and ACTION_UP for the release decision.

Why calculate position relative to full screen width?

It keeps the threshold consistent across screen sizes, instead of shifting based on the card's own width.

Can the same pattern work in Java?

Yes. The Kotlin implementation translates directly to Java with equivalent touch listener and animation APIs.

What's the threshold logic for accepting a swipe?

The card is accepted if the user drags it past the average position by a minimum distance before lifting their finger.

How do you extend the pattern for right-swipe support?

Mirror the position math to recognize rightward movement and add a second threshold or action to distinguish the two outcomes.

Related