In a previous article, I wrote about UISearchController and how to display a filtrable content in UIKit.
Now with SwiftUI modifiers, this task has become way easier and with just few lines of code you can have your search bar with data filtering up and running.
To implement this in your app, start by creating a new SwiftUI project in Xcode and open the ContentView.swift file
Add the following variables at the start of the ContentView struct:
@State private var searchText: String = "" private var cities = ["Amsterdam", "Bangkok", "Cairo", "Dubai", "Edinburgh", "Florence", "Geneva", "Helsinki", "Istanbul", "Jakarta", "Kuala Lumpur", "Lisbon", "Madrid", "Nairobi", "Oslo", "Paris", "Quito", "Rome", "Sydney", "Tokyo", "Ulaanbaatar", "Vienna", "Washington, D.C.", "Xanthi", "Yokohama", "Zurich"] @State private var filteredContent: [String] = []
searchText
will handle the text you type in the search bar, cities
is an array that serves as the list’s datasource while filteredContent
is the list’s second datasource that contains the result of data based on the user input to the search bar.
You can notice that both searchText
and filteredContent
are wrapped with the @State
property wrapper, this is because we need to allow SwiftUI to automatically update the view when these values change. You will see how this is done next.
Replace the body variable implementation to the following:
var body: some View { NavigationStack { List(filteredContent, id: \.self) { city in VStack { Text(city) } } } .onAppear { filteredContent = cities } .searchable(text: $searchText) .onChange(of: searchText) { filteredContent = searchText.isEmpty ? cities : cities.filter { $0.lowercased().contains(searchText.lowercased()) } } }
The List
will use filteredContent
array as a permanent datasource, however, when the view is appeared filteredContent
will clone the content from the cities
array. This allows to keep cities
as a static source of truth that is needed on some use cases (i.e: on view appear and on search bar text reset).
Whenever a user types in the search bar, the onChange modifier callback is called, at that time the filteredContent is changed based on two condition:
1- If the search bar is empty, the cities
array will be cloned in filteredContent
array and populated in the List.
2- If there is any text typed, we will filter over the cities
array, look for any element that contains the searched text string and add it to the filteredContent
array, then populate the List
with the result.
The paragraph can be revised for clarity and brevity as follows:
Notice the id: \.self
in the List
initializer. Since each element needs a unique identifier, in this case self
is used as unique identifier for each item of the list. This would change if the data source were a custom object model instead of simple strings. The unique identifier helps SwiftUI differentiate between the items and track their state. Its counterpart in UIKit is the UITableView cell reuse identifiers.
References: https://developer.apple.com/documentation/swiftui/adding-a-search-interface-to-your-app
Thanks for reading – see you in the next digest!
Discover more from SweetTutos
Subscribe to get the latest posts sent to your email.