Making SwiftUI Views Searchable
source link: https://useyourloaf.com/blog/making-swiftui-views-searchable/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
SwiftUI gains a search field in iOS 15. The searchable view modifier lets you make any content view searchable reducing the need to roll your own search bar.
Searching SwiftUI Views
If you’ve ever struggled with UIKit’s UISearchController
you’re probably going to like how much less effort it takes to add search to a SwiftUI view. Here’s a list of countries that I want to search:
The implementation of the view is plain list in a navigation view:
struct WorldView: View {
@FetchRequest(sortDescriptors: [SortDescriptor(\.name)])
private var countries: FetchedResults<Country>
var body: some View {
NavigationView {
List(countries) { country in
NavigationLink(destination:
CountryView(country: country)) {
CountryCell(country: country)
}
}
.listStyle(.plain)
.navigationTitle("World")
NoCountrySelected()
}
}
}
I’m using Core Data to store the country objects but that’s not a requirement (see Configuring SwiftUI Fetch requests for a recap).
The Searchable View Modifier
To get started with adding search to our list we need a state variable to store our search query text:
@State private var query = ""
Then we add the .searchable
view modifier to our content view. Note that you are not limited to searching lists, you can add the modifier to any content view:
NavigationView {
}
.searchable(text: $query)
Finally, we use a change in the query text to update our fetch request to generate new results:
NavigationView { ...
}
.searchable(text: $query)
.onChange(of: query) { newValue in
countries.nsPredicate = searchPredicate(query: newValue)
}
Since we’re using Core Data we update the predicate of the fetch request using the query text:
private func searchPredicate(query: String) -> NSPredicate? {
if query.isBlank { return nil }
return NSPredicate(format: "%K BEGINSWITH[cd] %@",
#keyPath(Country.name), query)
}
}
Placeholder Text
By default, the search field shows a localized search prompt:
You can override this by adding a prompt to the searchable view modifier:
.searchable(text: $query, prompt: "Search countries")
Search Bar Placement
The search bar appears in a position appropriate to the platform. When used with a navigation view on iOS and iPadOS it defaults to applying to the primary view of a two column split view or the second column of a triple column view. You can always override that by adding the modifier directly on the desired column.
You can also change the preferred placement of the search field within the containing view hierarchy. The default is to place the search field automatically depending on the platform. You can override the default to prefer the navigationBarDrawer
, sidebar
or toolbar
:
.searchable(text: $query, placement: .sidebar)
Note this has no effect in my example as I don’t have a sidebar. When shown below the navigation bar, the search bar collapses under the bar when the user scrolls. You can override that to keep the search bar visible by changing the display mode:
.searchable(text: $query,
placement: .navigationBarDrawer(displayMode: .always))
isSearching and dismissSearch
The isSearching
environment variable tells you if the user is interacting with a search field:
@Environment(\.isSearching)
private var isSearching: Bool
In the WWDC session video (see below) they use this to present the search results in an overlay. I’ve also found it useful when I want to show a search scope bar when the user is searching:
if isSearching {
ScopeBar(selected: $searchBy)
}
The dismissSearch
environment property gives you a method that dismisses an active search:
@Environment(\.dismissSearch)
private var dismissSearch
Calling dismissSearch()
will also set isSearching
to false:
if isSearching {
Button("Dismiss") {
dismissSearch()
}
}
Search Submit Action
If you only want to perform the search when the user submits the query add an onSubmit
action:
.onSubmit(of: .search) {
// perform query
}
Search Suggestions
Finally, you can provide a search suggestions view as part of the searchable view modifier:
.searchable(text: $scope.beginsWith) {
ForEach(suggestions) { suggestion in
Text(suggestion.title).searchCompletion(suggestion.completion)
}
}
I’m using Text
views but you can use any view. The search completion provides the text that replaces the search query when the user selects a suggestion. I’m using a static list of suggestions, but you could generate them dynamically based, for example, on search history:
struct SearchSuggestion: Identifiable {
var id: Int
var title: String
var completion: String
}
private var suggestions = [
SearchSuggestion(id: 1, title: "🇨🇦 Canada", completion: "Canada"),
SearchSuggestion(id: 2, title: "🇬🇧 UK", completion: "United Kingdom"),
SearchSuggestion(id: 3, title: "🇺🇸 USA", completion: "United States")
]
Learn More
Recommend
-
52
Part 2 in a series on understanding data in SwiftUI. We will talk about the key that makes principles inpart 1 possible in SwiftUI. And how this resulting in a reduction of the complexity of UI development.
-
49
With SwiftUI layers can be added on top of the view. This can be done with the .overlay modifier. In this tutorial a text view is displayed on top of an image using an overlay.SwiftUI requires Xcode 11 and MacOS Catalina...
-
33
Combine is one of the new frameworks released during WWDC 2019. It provides a declarative Swift API for processing values over time. Today we will talk about one of the hidden features of SwiftUI...
-
18
SwiftUI provides us a very fast and easy to use diffing algorithm, but as you might know, diffing is a linear operation. It means that diffing will be very fast for simple layouts and can take some time for a c...
-
25
A few weeks ago, we talked about building views like PagerView and BottomSheetView from scratch in SwiftUI . SwiftUI is pretty young and misses some components that we expect to hav...
-
28
This week I want to continue the topic of layout system in SwiftUI . The SwiftUI layout engine works predictably, and usually, an outcoming result looks like we expect. Today, to make this process even...
-
9
I built a proof-of-concept tool to render SwiftUI to HTML. While I’m not intending to turn it into a full UI framework, I still learned plenty along the way: I learned how to use Swift’s generic...
-
12
WWDC20 Session 10033 - Build SwiftUI views for widgets 本文知识目录
-
10
Searchable modifier in SwiftUI: A UISearchController and UISearchBar equivalent 07 Jul 2021 ⋅ 16 min read ⋅ SwiftUI
-
8
Making Your Jekyll Blog Searchable with HTML, JavaScript and Google Nov 22, 2019 So yesterday someone said this to me: You know the problem with your blog – you wri...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK