SwiftUI Tutorial: Adding Search Functionality to a List View (TodoList app)
In this tutorial, we will demonstrate the use of the .searchable
modifier in SwiftUI by adding a search feature to our Todo List app. Users will be able to search for specific tasks or todos based on their titles. We'll walk you through the steps to implement this feature, building upon the Todo List project from a previous tutorial.
Prerequisites
Before proceeding with this tutorial, make sure you have completed the following tutorial, as we will be building upon the existing Todo List app: SwiftUI Tutorial: Displaying collection data with List View — Todolist App
If you haven’t completed the Todo List app yet, we recommend going through the above tutorial first.
Overview
In the Todo List app, we’ll add a search bar to the user interface, allowing users to easily find specific tasks by typing in keywords. As the user enters text into the search bar, the app will dynamically filter the todo items and display only those that match the search keyword.
Adding Search Bar User Interface
First, open ContentView.swift
, where the main view of the Todo List app is defined. To store the user-typed keyword for searching, add a new @State
variable:
// MARK: user typed keyword
@State var searchKeyword: String = ""
Next, let’s integrate the .searchable
modifier into our List
view and bind it to the searchKeyword
variable:
List {
// List content...
}
.listStyle(.inset)
.padding()
.navigationTitle("Todo List")
// MARK: Add searchable modifier
.searchable(text: $searchKeyword)
By adding the .searchable
modifier to the List
, we enable the search functionality and bind the search text to the searchKeyword
variable.
This is our updated ContentView code:
struct ContentView: View {
// MARK: user typed keyword
@State var searchKeyword: String = ""
var body: some View {
NavigationView {
List {
ForEach(todos, id: \.self) { todo in
NavigationLink(destination: TodoDetailView(todo: todo)) {
HStack(alignment: .center) {
VStack(alignment: .leading) {
Text(todo.title)
.font(.title3)
Text(formatDate(todo.date))
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()
StatusIndicator(status: todo.status)
}
}
}
}
.listStyle(.inset)
.padding()
.navigationTitle("Todo List")
// MARK: Add searchable modifier
.searchable(text: $searchKeyword)
}
}
private func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter.string(from: date)
}
}
Implementing Search Filtering
With the search bar in place, we can now implement the logic to filter the todo list based on the user’s search input. We need a new variable to hold the filtered result, but we don’t want to modify the original todos
variable to preserve the original data. Below the searchKeyword
state, add a new computed property called results
:
var results: [Todo] {
return searchKeyword.isEmpty ? todos : todos.filter({ todo in
todo.title.contains(searchKeyword)
})
}
The results
variable returns the filtered todos
array. If the searchKeyword
is empty, we show all todos. Otherwise, we use the filter
method to find todos whose titles contain the searchKeyword
.
Updating List Data Source
Now that we have the results
variable containing the filtered todos, we need to update the List
to use this data source. Replace todos
with results
in the ForEach
loop:
ForEach(results, id: \.self) { todo in
// Todo item content...
}
With this change, the List
will now display only the todos that match the search keyword, and it will automatically update as the user types in the search bar.
Final ContentView Code
Here’s the final code for the ContentView
with the search functionality implemented:
import SwiftUI
struct ContentView: View {
// MARK: user typed keyword
@State var searchKeyword: String = ""
var results: [Todo] {
return searchKeyword.isEmpty ? todos : todos.filter({ todo in
todo.title.lowercased().contains(searchKeyword.lowercased())
})
}
var body: some View {
NavigationView {
List {
ForEach(results, id: \.self) { todo in
NavigationLink(destination: TodoDetailView(todo: todo)) {
HStack(alignment: .center) {
VStack(alignment: .leading) {
Text(todo.title)
.font(.title3)
Text(formatDate(todo.date))
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()
StatusIndicator(status: todo.status)
}
}
}
}
.listStyle(.inset)
.padding()
.navigationTitle("Todo List")
// MARK: Add searchable modifier
.searchable(text: $searchKeyword)
}
}
private func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter.string(from: date)
}
}
With the above code, your Todo List app will now have a search bar that allows users to easily find tasks by their titles. As they type in the search bar, the list will be updated dynamically to display only the relevant todo items. This feature enhances the usability and user experience of the app, making it more efficient to manage tasks. Feel free to explore and customize the app further to suit your needs!
Finish Project on Github
https://github.com/drawrs/SwiftUI-Simple-TodoList/tree/searchable