Building a To-Do App with RecyclerView and Swipe-to-Delete in Android

Android development in Australia has grown steadily, with active communities from Sydney through to Perth. Local meetups like GDG Sydney and RMIT coding circles in Melbourne run workshops on modern Android tooling, making it easier for newcomers to learn RecyclerView and gesture handling. Whether you're a hobbyist in Adelaide or a freelancer in Noosa, building a small to-do app remains one of the best ways to learn Android's UI components.

A to-do list is a brilliant learning project because it covers data display, user input, persistence, and interaction patterns. The RecyclerView component has largely replaced the older ListView, giving you finer control over how rows are recycled and rendered. Add a swipe gesture to delete a task, and you have a polished interaction that mirrors what most modern apps already do.

We'll work through the data layer, the adapter, the layout, and the gesture handling in sequence. The code samples assume you're using Android Studio Hedgehog or newer and that you're comfortable with Kotlin basics. For deeper reference, the tutorials at android tutorial point cover custom adapters and DiffUtil in more detail.

Setting Up Your Android Studio Project

Start by creating a new project in Android Studio with an Empty Activity template. Choose Kotlin and set the minimum SDK to API 24 so you reach the vast majority of Australian devices on Android 7.0 and up. Once the project loads, open your build.gradle file and add the Material Components dependency, which gives you access to MaterialCardView, swipe backgrounds, and the modern colour tokens that align with Material 3.

Inside res/values, define a fresh colour palette. Australians love a coastal aesthetic, so lean into blues and sandy tones. Switch your activity layout to use a Theme.Material3.DayNight parent so the app responds to system dark mode — a feature many Aussie users toggle in the evening.

Before jumping into code, confirm your project structure looks tidy. Right-click your package, create folders named data, ui, and util, and move your MainActivity.kt into the UI folder. Future-you will appreciate it when the project grows beyond a weekend experiment.

Designing the Data Model and Adapter

A to-do item needs three pieces of information at minimum: an identifier, a title, and a completion state. Define a simple data class called Task with an autogenerated id, a title string, and a isDone boolean. Keep the class immutable where possible. This separation makes it easier to swap in a Room database later without rewriting your UI code.

Next, build a TaskAdapter that extends RecyclerView.Adapter<TaskAdapter.TaskViewHolder>. Inside the view holder, inflate a layout called item_task.xml that contains a CheckBox, a TextView, and a root ConstraintLayout. Bind the title and checkbox state inside onBindViewHolder, and wire up the checkbox listener to update the underlying task.

When you create the adapter, pass it a lambda for delete actions like onTaskDeleted: (Task) -> Unit. This callback pattern keeps the activity in charge of data manipulation while the adapter stays focused on rendering.

Implementing RecyclerView in Your Layout

Open activity_main.xml and drop a RecyclerView widget into a ConstraintLayout. Give it match-parent constraints, an ID like taskRecyclerView, and set layoutManager to LinearLayoutManager from the XML attributes. Add an empty state view underneath — a TextView saying something like "Nothing on the list yet, have a brekkie and start fresh" — and toggle its visibility based on whether the list is empty.

Inflate the layout in MainActivity, instantiate the adapter, and attach it to the RecyclerView. Set a default item animator so additions and removals animate smoothly out of the box. A bit of local personality in your copy helps the project feel handcrafted rather than generic. For testing the layout, hardcode a small list of fake tasks inside the activity's onCreate so you can validate the wiring before adding gestures.

Handling Item Touches and Gestures

Gesture handling in RecyclerView is delegated to a helper class called ItemTouchHelper. You attach an instance to your RecyclerView, and the helper manages touch events for you. The constructor takes a callback where you implement the movement and swipe directions that you want to support. For a to-do app, enable LEFT and RIGHT swipe directions but no drag-and-drop movement.

Inside the callback, override onSwiped to receive the viewHolder that the user swiped away. Look up the task at that position using adapter.currentList[position], then call your delete lambda. Be careful to capture the position before the list updates — otherwise, the adapter's submitList call may swap indices underneath you. Many developers in Melbourne's startup scene like to wrap the deletion in a Snackbar so accidental swipes can be undone, which is a polish step we'll revisit shortly.

Adding Swipe-to-Delete with ItemTouchHelper

Now wire the helper into the RecyclerView. Create an ItemTouchHelper.SimpleCallback with 0 for drag directions and ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT for swipe directions. Inside onSwiped, call the adapter's remove callback and submit the updated list to a ListAdapter. If you're using a regular RecyclerView.Adapter, mutate your backing list directly and call notifyItemRemoved(position).

To make the swipe look good, override onChildDraw and paint a coloured background plus a trash icon behind the row as it slides. Use ContextCompat.getDrawable to load a vector icon, positioned on the swipe side. For an Australian palette, a muted red or charcoal background pairs nicely with a white delete icon without violating accessibility contrast.

Once the helper is built, attach it with attachToRecyclerView(taskRecyclerView) from MainActivity. Run on a physical device if you can — emulators sometimes handle swipe thresholds inconsistently. For a thorough guide on testing tools that complement this kind of build, the thucydides-webtests.com resource outlines several patterns worth borrowing.

Persisting Tasks with Room or SharedPreferences

For simple projects, SharedPreferences works fine, but Room gives you proper query support and scales to richer data later. Add the Room dependencies, define a TaskDao with insert, update, delete, and observe queries, and convert your Task data class into a @Entity.

If Room feels like overkill, serialise the task list to JSON using Gson or Kotlinx Serialization and store it in a single SharedPreferences entry. This approach is what some Australian indie devs ship in their weekend prototypes because it requires almost zero boilerplate.

Wire your repository into a ViewModel using viewModels() and ViewModelProvider.Factory. The activity observes the list with repeatOnLifecycle(STARTED) so updates survive configuration changes. With persistence in place, you can confirm your list survives a cold start.

Polishing the UX with Animations and Undo

A swipe-to-delete interaction feels incomplete without an undo path. Wrap your delete logic in a Snackbar with an Undo action that reinserts the task at its original position. Use Snackbar.LENGTH_LONG so users have a few seconds to react.

For a more refined touch, customise the swipe background to fade in based on swipe velocity rather than appearing instantly. You can read the velocity from dx and dy values passed into onChildDraw and adjust the background drawable's alpha accordingly. Subtle effects like this are what distinguish a polished portfolio project from a tutorial clone.

Storage Option Best For Setup Complexity Query Support
SharedPreferences (JSON) Weekend prototypes, simple lists Low None — manual parsing
Room Database Production apps, complex queries Medium Full SQL via DAO
DataStore (Preferences) Typed key-value settings, not lists Low None
DataStore (Proto) Structured data with schema Medium Partial

Once you've nailed the basics, consider extending the app with due dates, categories, or reminders using WorkManager. Many Australian developers release to-do apps as their first Play Store listing, and the patterns you learn here translate directly to richer apps later on.

Time to start building. Fire up Android Studio, scaffold a fresh project, and work through each section one at a time. When you hit a snag, lean on the broader community — post questions in GDG Sydney's Slack, browse the Android documentation, or check the detailed walkthroughs. Ship code and keep iterating.