skip to Main Content

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


  1. 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:

    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))
            .onChange(of: searchText) { newValue in
                showingTags = newValue.isEmpty
            }
        }
    }
    

    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().

    Login or Signup to reply.
  2. You can use the environment value isSearching to detect if the search text field is focused.

    You should declare an Environment, not in ProductSearchView, but in one of the subviews of the searchable view. Since this determines the visibility of the TagView, it’s probably the easiest if you put it in TagView:

    struct TagView: View {
        @Environment(.isSearching) var isSearching: Bool
        var body: some View {
            if !isSearching {
                // put the original contents of "body" here...
            }
            // if isSearching is true, then the body is empty. The view is basically "hidden".
        }
    }
    

    Now you don’t even need showingTags!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search