Designing a Calm Bulk-Delete Interaction on Android
When an app updates frequently, removing content can be just as important as adding it.
In DealPing, deals arrive continuously. Over time, the inbox fills up with items the user has already seen. Clearing those items should feel fast and intentional — not destructive or jarring.
This post walks through the design and implementation of a Bulk-Delete interaction on Android, and why subtle motion made a big difference.
The problem
DealPing surfaces new deals continuously. Items are added often, and users regularly want to remove:
- Clear All
- Unpin All Deals
Functionally, this is simple. But visually, bulk deletion can feel harsh on Android:
- items disappear instantly
- the list collapses abruptly
- the UI feels like it “jumps” rather than responds
Nothing was broken — but the experience felt heavier than it needed to be.
The constraint
This wasn’t about showing off animations.
The goal was very specific: make deletion feel calm, reversible, and cheap to render — even when many items are removed at once.
That meant:
- no dramatic transitions
- no blocking the main thread
- no full list re-renders
Just enough motion to help the user understand what changed.
The Solution: Native Layout Animation
React Native provides a powerful API called LayoutAnimation that allows the native layout system to automatically animate changes in the UI.
On Android, LayoutAnimation is considered an experimental feature of the UIManager and is disabled by default. If you try to use it without initialization, nothing happens—your layout changes remain instant and jagged.
To fix this, we need to explicitly enable the experimental layout animation manager at the start of our app lifecycle.
Best Practice: Place this check in your Root Layout (_layout.tsx or App.tsx) so it runs once at startup.
// app/_layout.tsx
import { Platform, UIManager } from "react-native";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
Once enabled, we can tell the layout engine to animate the next layout cycle. This is perfect for list operations like "Clear All Read" or deleting a single item.
import { LayoutAnimation } from "react-native";
const handleClear = () => {
// 1. Configure the NEXT layout update to be animated
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
// 2. Perform the state update (which triggers the layout change)
clearReadDeals();
};
The Result
By adding just a few lines of code, we transformed a functional-but-abrupt interaction into a smooth, high-quality experience.
iOS (Reference)
Android (Parity)
The "snap" is gone, and Android users now get the same level of polish as their iOS counterparts.
It's a small detail, but in a mobile app, details are everything.