Imagine scrolling through your to-do list app. You spot an old task. No delete button in sight. You hunt for settings. Frustration builds fast.
Swipe-to-dismiss fixes that. Drag an item sideways. It slides away smooth. Think Gmail inbox clears. Long-press adds more. Hold your finger down. Options pop up like edit or share.
This guide shows you how to build both in an Android app. We’ll use Kotlin, RecyclerView, and ItemTouchHelper. You get a working to-do list demo. First, install Android Studio. Know basic Kotlin. Let’s start with project setup.
Setting Up Your RecyclerView Project
Start fresh. Open Android Studio. Create a new project. Pick Empty Activity with Kotlin. Name it TodoGestures. Set minimum SDK to 24. That covers most devices.
Next, add RecyclerView. Open app/build.gradle. In dependencies, add these lines:
implementation "androidx.recyclerview:recyclerview:1.3.2"
implementation "androidx.cardview:cardview:1.0.0"
Sync the project. RecyclerView handles long lists well. It recycles views off-screen. Your app stays fast.
Now, build the layout. Edit activity_main.xml. Add a RecyclerView that fills the screen:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Create item_todo.xml for each list item. Use CardView for elevation. Inside, add a TextView for the task title.
Make a data class. Call it TodoItem:
data class TodoItem(val id: Int, val title: String)
Build the adapter. Name it TodoAdapter. Extend RecyclerView.Adapter<TodoAdapter.ViewHolder>. Create ViewHolder with itemView and title TextView.
Override onCreateViewHolder. Inflate item_todo.xml. Return new ViewHolder.
In onBindViewHolder, set titleTextView.text = todoItem.title. Add a stub for long-click later.
Override getItemCount as list.size.
In MainActivity, set content view. Find recyclerView. Use LinearLayoutManager(this). Add it with recyclerView.layoutManager = manager.
Create fake data. Make a mutableListOf. Add five tasks like “Buy milk” or “Call mom”.
Set adapter = TodoAdapter(dataList). recyclerView.adapter = adapter.
Run the app. See your list. Items look clean. Add dividers with DividerItemDecoration for polish. Pass it to recyclerView.addItemDecoration.
This base works solid. Gestures come next without mess.
Create the Project and Add Dependencies
Launch Android Studio. Click New Project. Choose Empty Activity. Select Kotlin. Enter package name com.example.todogestures. Finish.
Why SDK 24? It supports 95% devices. Stable for gestures.
In build.gradle (Module: app), dependencies block gets RecyclerView. Sync now. Gradle downloads it. ItemTouchHelper comes built-in with RecyclerView.
Build Your List Layout and Adapter
Main layout stays simple. RecyclerView takes all space. No extra views distract.
Item layout uses CardView. Set app:cardCornerRadius=”8dp”. TextView gets padding. Center text.
Adapter holds MutableList. ViewHolder binds in onBind. Use findViewById for title.
MainActivity populates data. Then adapter.notifyDataSetChanged(). List appears instant.
Add Swipe-to-Dismiss for Effortless Deletes
Users love quick deletes. ItemTouchHelper detects swipes easy. Extend SimpleCallback. Focus on swipe, skip drag.
Create SwipeToDismissCallback. Pass adapter reference in constructor.
Override getMovementFlags. Return makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT). Swipe either way works.
Override onMove? Return false. We skip reordering.
In onSwiped, get viewHolder.adapterPosition. Call adapter.removeItem(position).
Attach it. In MainActivity, val callback = SwipeToDismissCallback(adapter). val helper = ItemTouchHelper(callback). helper.attachToRecyclerView(recyclerView).
Test now. Swipe an item. It flies off-screen. List updates smooth.
Default animation feels native. Items shift up fast.
Create the Swipe Callback Class
Class SwipeToDismissCallback(adapter: TodoAdapter) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
return makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT)
}
override fun onMove(…) = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.adapterPosition
adapter.removeItem(position)
}
}
Pass adapter so it removes items.
Attach Helper and Handle Item Removal
MainActivity creates helper after adapter. Attach to recyclerView.
Add removeItem to TodoAdapter. It does dataList.removeAt(position). notifyItemRemoved(position).
Simple. No DiffUtil yet for beginners. Keeps it light.
Smooth Out the Dismiss Animation
ItemTouchHelper animates out-of-box. Item shrinks and slides.
Customize? Override getAnimationDurationMillis in callback. Return 200L for quicker feel.
Add undo. In onSwiped, before remove, show Snackbar.make(recyclerView, “Item dismissed”, Snackbar.LENGTH_LONG).setAction(“Undo”) { adapter.restoreItem(position) } .show()
Restore adds back to list. Notifies adapter. Users smile.
Bring Long-Press to Life for Extra Options
Swipe deletes. Long-press opens doors. Set listener in ViewHolder.
In onBindViewHolder, itemView.setOnLongClickListener {
showOptions(adapterPosition)
true // Consume event, block swipe
}
True stops other gestures. No conflicts.
showOptions takes position. Builds PopupMenu at itemView.
Inflate menu with edit, share, delete.
Handle clicks. Edit shows dialog. Share uses Intent. Delete removes.
Add Vibration. Use (context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator).vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE))
Feels premium.
Set Up Long-Press Listeners in Your Adapter
ViewHolder has itemView. In onBind, set listener as above.
showOptions(pos: Int) { … } goes in adapter. Access dataList[pos].
Return true always. Eats the event.
Display a Popup Menu with Useful Actions
Create res/menu/popup_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/edit" android:title="Edit" />
<item android:id="@+id/share" android:title="Share" />
<item android:id="@+id/delete" android:title="Delete" />
</menu>
In showOptions: PopupMenu(itemView.context, itemView).menuInflater.inflate(R.menu.popup_menu, menu)
menu.setOnMenuItemClickListener { item ->
when(item.itemId) {
R.id.edit -> showEditDialog(pos)
R.id.share -> shareItem(dataList[pos])
R.id.delete -> removeItem(pos)
}
true
}
.show()
Edit dialog: AlertDialog.Builder. Set text input. Update dataList[pos].title on save. notifyItemChanged(pos)
Share: Intent(Intent.ACTION_SEND).putExtra(Intent.EXTRA_TEXT, title).startActivity()
Clean actions.
Test and Perfect Your Gesture Combo
Build and run. Emulator first. AVD with API 30 works.
Swipe items. Long-press others. No overlap.
Real phone next. USB debug. Gestures feel better on touch.
Log positions. Add Log.d(“Gestures”, “Swiped $position”) in callbacks.
Edge cases: Swipe first item. Long-press last. Empty list? Show message.
Icons help. Add ImageView in item layout for trash hint.
Run Tests on Emulators and Phones
Run > Run ‘app’. Emulator swipes okay. Install APK on phone via Build > Build Bundle/APK.
Test fast swipes. Slow holds. All items.
Empty list: if(dataList.isEmpty()) show TextView “No tasks”.
Fix Common Issues and Add Polish
Swipe too easy? Override getSwipeThreshold(0.5f) in callback.
Long-press ignores? Check return true. Padding blocks? Set on root view.
Ripple: itemView.background = RippleDrawable.
Shadows: CardView elevation 4dp.
Accessibility: titleTextView.contentDescription = “Task: $title”
ViewHolder recycles right. No leaks.
Tweak colors. Blue for swipe background in callback’s onChildDraw.
Your list shines now.
Simple gestures changed everything. You built swipe-to-dismiss and long-press from scratch. Your to-do app delights users.
Tweak the code. Add to your projects. Share below: what app gets these next? Subscribe for drag-reorder tips soon.
Gestures earn loyalty fast. Start coding.