In this SwiftUI code, I have a view that contains a search bar and underneath the search bar are some filter tags that are in a capsule shape & an image.
When the search bar is tapped, the keyboard shifts up the view and the filter tags cover the search bar.
I want to alter the code so that showingTags is set to false when the search bar has been tapped in order to avoid this UI error
I tried using .onTapGesture{} on the .searchable modifier but this didn’t seem to work. How can I make sure the tags are not shown when the search bar has been tapped?
Here is my code:
struct ProductSearchView: View {
@StateObject var marketplaceModel = MarketplaceViewModel()
@State var searchText = ""
@State var product_array_status = true
@State var product_array_status_search = false
@State var product_array_status_tags = false
@State var showingTags: Bool = true
var body: some View {
ZStack {
Color("BG")
.ignoresSafeArea()
VStack {
if showingTags {
TagView()
}
if product_array_status_search {
VStack(spacing: 15) {
ScrollView(.vertical, showsIndicators: false) {
ForEach(marketplaceModel.filteredProduct.filter { ($0.product_name ?? "").contains(searchText)}, id: .self) { product in
ProductSearchRow(productData: product)
}
}
}
.onAppear {
showingTags.toggle()
}
} else if product_array_status_tags {
VStack(spacing: 15) {
ScrollView(.vertical, showsIndicators: false) {
ForEach(marketplaceModel.product_tag_array, id: .self) { product in
ProductSearchRow(productData: product)
}
}
}
} else {
Image("PlaceholderImage")
.resizable()
}
Spacer()
}
}
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always))
.onAppear {
let defaults = UserDefaults.standard
let keyString = defaults.string(forKey: "key") ?? ""
self.marketplaceModel.fetchProductData(key: keyString)
}
.onChange(of: marketplaceModel.search, perform: { value in
// to avoid Continues Search requests....
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
if value == marketplaceModel.search && marketplaceModel.search != ""{
// Search Data....
marketplaceModel.filterData()
}
}
if marketplaceModel.search == ""{
// reset all data....
withAnimation(.linear) {
product_array_status = true
product_array_status_search = false
}
}
})
}
}
How do I ensure TagView() is not displayed when the search bar provided by .searchable has been tapped?
2
Answers
To ensure that TagView() is not displayed when the search bar provided by .searchable has been tapped, you can utilize the .onChange(of:perform:) modifier to detect alterations in the searchText variable. When the searchText changes, you can verify if it is devoid of content or not. If it is not empty, it signifies that the search bar has been tapped, so you can assign showingTags a value of false. Here’s an updated version o f your code with the modification:
In this code, the .onChange(of:perform:) modifier is added after the .searchable modifier. It observes modifications in the searchText variable and triggers the closure whenever the value changes. Inside the closure, it checks if the searchText is empty, indicating that the search bar has been tapped. If it is empty, showingTags is set to true, which hides the TagView().
You can use the environment value
isSearching
to detect if the search text field is focused.You should declare an
Environment
, not inProductSearchView
, but in one of the subviews of thesearchable
view. Since this determines the visibility of theTagView
, it’s probably the easiest if you put it inTagView
:Now you don’t even need
showingTags
!