Reputation: 1080
I am using the new SwiftUI searchbar .searchable
. In conjunction with this, I am using a method that allows an action to be performed when search is clicked: .onSubmit(of: .search) {
The issue I am having is I cannot figure out how to dismiss the searchbar when .onSubmit
is triggered.
the .onSubmit
is working fine and I am able to call functions from inside of it, but cannot figure out how to dismiss the searchbar itself. The keyboard disappears, but the searchbar itself remains in an active state.
I have tried resorting to UIKit methods, but they do not seem compatible.
Any ideas?
Upvotes: 1
Views: 1113
Reputation: 378
The accepted answer is not quite correct. I just came across this problem and did not want to get my same question flagged as duplicate so I asked on the Apple Forums and had help finding a solution.
In order to call dismissSearch from a parent view's .onSubmit(of: .search) one must find a way to store the reference to the child view's dismissSearch environment value in a way that the parent can call it. For example, use a ViewModel of some kind to store a function that you can overwrite from the child with the child's dismissSearch environment value when it becomes available in an onAppear or something similar.
class ViewModel {
var dismissClosure: () -> Void = { print("Not Set") }
}
Pass this ViewModel to the child and then store the dismissSearch in the child so the parent can call it from the shared ViewModel
.onAppear {
viewModel.dismissClosure = { dismissSearch() }
}
Here is the complete solution to the posted problem that can pasted into an Xcode Playground to test it out.
import SwiftUI
import PlaygroundSupport
class ViewModel {
var dismissClosure: () -> Void = { print("Not Set") }
}
struct SearchingExample: View {
@State var searchText = ""
@State var didSubmit = false
@Environment(\.dismissSearch) var dismissSearch
let viewModel = ViewModel()
var body: some View {
NavigationStack {
SearchedView(didSubmit: $didSubmit, viewModel: viewModel)
.searchable(text: $searchText)
.onSubmit(of: .search) {
didSubmit = true
viewModel.dismissClosure()
}
}
}
}
struct SearchedView: View {
@Environment(\.isSearching) var isSearching
@Environment(\.dismissSearch) var dismissSearch
@Binding var didSubmit: Bool
let viewModel: ViewModel
var body: some View {
VStack {
Text(isSearching ? "Searching!" : "Not searching.")
Button(action: { dismissSearch() }, label: {
Text("Dismiss Search")
})
Button(action: {
// Return Key for playground
}, label: {
Image(systemName: "paperplane")
})
.frame(width: 30, height: 30)
.keyboardShortcut(.defaultAction)
if didSubmit {
Text("You Submitted Search!")
.onAppear {
Task { @MainActor in
try await Task.sleep(nanoseconds: 3_000_000_000)
self.didSubmit = false
}
}
}
}
.onAppear {
viewModel.dismissClosure = { dismissSearch() }
}
}
}
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.setLiveView(SearchingExample())
Upvotes: 1
Reputation: 614
There is a new environment value
@Environment(\.dismissSearch) var dismissSearch
that you can call as a function to dismiss the searchbar.
Upvotes: 2