2

I followed this tutorial to add a SearchBar on my SwiftUI app: http://blog.eppz.eu/swiftui-search-bar-in-the-navigation-bar/ It basically uses a custom modifier to add the SearchBar into NavigationView:

extension View {
    
    func add(_ searchBar: SearchBar) -> some View {
        return self.modifier(SearchBarModifier(searchBar: searchBar))
    }
}

Since I my NavigationView wrap a TabView, and I only want to show SearchBar in specified tab (e.g. second tab has SearchBar, the others don't). I would like to hide or remove searchBar view but I couldn't find any way to do it. Please help

This is how I wrap NavigationView outside of TabView:

struct MainView: View {
    @ObservedObject var searchBar = SearchBar()
    @State private var selectedTab :Int = 0
    private var pageTitles = ["Home", "Customers","Sales", "More"]
    
    
    var body: some View {
        NavigationView{
            TabView(selection: $selectedTab, content:{
                HomeView()
                    .tabItem {
                        Image(systemName: "house.fill")
                        Text(pageTitles[0])
                    }.tag(0)
                CustomerListView(searchText: searchBar.text)
                    .tabItem {
                        Image(systemName: "rectangle.stack.person.crop.fill")
                        Text(pageTitles[1])
                    }.tag(1)
                SaleView()
                    .tabItem {
                        Image(systemName: "tag.fill")
                        Text(pageTitles[2])
                    }.tag(2)
                
                MoreView()
                    .tabItem {
                        Image(systemName: "ellipsis.circle.fill")
                        Text(pageTitles[3])
                    }.tag(3)
            })
            .add(searchBar, when: selectedTab == 1)            
        }
    }
}


//Compile error: Function declares an opaque return type, but the return statements in its body do not have matching underlying types
    extension View {
        func add(_ searchBar: SearchBar, when: Bool) -> some View {
            if(when == true)
                return self.modifier(SearchBarModifier(searchBar: searchBar))
            else
                return self
        }
    }
Nguyen Minh Binh
  • 23,891
  • 30
  • 115
  • 165

3 Answers3

2

Try to make it view builder (or wrap condition in Group {})

extension View {

    @ViewBuilder
    func add(_ searchBar: SearchBar, when: Bool) -> some View {
        if when == true {
           self.modifier(SearchBarModifier(searchBar: searchBar))
        } else {
           self
        }
    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • the app can be compiled and runs now but SearchBar still showing on other tabs. when it's added to NavigationView, it seems visible there permanently – Nguyen Minh Binh Apr 22 '21 at 07:38
1

searchable work with single child view after NavigationView. So my modification is to remove the parent NavigationView and add NavigationView in the individual View. but don't know about the best options.

struct MainView: View {
    @ObservedObject var searchBar = SearchBar()
    @State private var selectedTab :Int = 0
    private var pageTitles = ["Home", "Customers","Sales", "More"]
    
    
    var body: some View {
            TabView(selection: $selectedTab, content:{
                NavigationView{
                  HomeView()
                      }
                    .tabItem {
                        Image(systemName: "house.fill")
                        Text(pageTitles[0])
                    }.tag(0)
                NavigationView{
                CustomerListView(searchText: searchBar.text)
                    .searchable(text: $searchText)

                  }
                    .tabItem {
                        Image(systemName: "rectangle.stack.person.crop.fill")
                        Text(pageTitles[1])
                    }.tag(1)
              NavigationView{
                SaleView()
               }
                    .tabItem {
                        Image(systemName: "tag.fill")
                        Text(pageTitles[2])
                    }.tag(2)
                NavigationView{
                MoreView()
                }
                    .tabItem {
                        Image(systemName: "ellipsis.circle.fill")
                        Text(pageTitles[3])
                    }.tag(3)
            })
            //.add(searchBar, when: selectedTab == 1)            
        }
    }
}
Md Tariqul Islam
  • 2,736
  • 1
  • 20
  • 35
1

There is article on how to do conditional view modifiers at SwiftLee:

https://www.avanderlee.com/swiftui/conditional-view-modifier/

It basically adds an extension to View like this:

extension View {
    @ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}

Then you can use it as:

...
TabView(selection: $selectedTab, content: {
    // your views
}.if(shouldApplySearch) { view in
    view.searchable {
        // searchable code  
    }
}

I'm using this to show a search bar for only 2 of 3 tab pages.

Jens
  • 6,243
  • 1
  • 49
  • 79