0

I am trying to use a tab bar in order to use different views. On some of those views I have a list of items and I wish that list to be .searchable. If I go to each of the views and search it works like a charm, but when I embed that in the tabbed view the list becomes non-responsive to click but it responds to scroll gesture.

I will expand the idea with code that I have and screenshots, but I am pretty sure that the problem resides in how I'm implementing the combination of the tab bar view and the views that have the searchable modifier:

This code works well

import SwiftUI

struct ClientListView: View {
    @ObservedObject var viewModel = ClientFeedViewModel()
    @State var searchText: String
    @State private var showingSheet = false
    @State private var showList = false
    
    var clients: [Client] {
        if searchText.count > 2 {
            return searchText.isEmpty ? viewModel.clients : viewModel.search(withText: searchText)
        }
        return viewModel.clients
    }
    
    init(){
        searchText = ""
    }
    
    var body: some View {
        NavigationView {
                List(clients) { client in
                    NavigationLink(destination: {
                        
                    }, label: {
                        VStack {
                            Text(client.clientName)
                        }
                    })
                    
                    .listRowSeparator(.hidden)
                }
                .searchable(text: $searchText)
                .listStyle(.plain)
        }
    }
}

struct ClientListView_Previews: PreviewProvider {
    static var previews: some View {
        ClientListView()
    }
}

The problem starts when I do this and implement the ClientListView in a tab bar view like this: Tab bar with different views not working searchable modifier

This is the code of the Tab Bar View:

import SwiftUI

struct MainTabView: View {
    @EnvironmentObject var viewModel: AuthViewModel
    @Binding var selectedIndex: Int
    
    var body: some View {
        NavigationView {
            VStack {
                TabView(selection: $selectedIndex) {
                    ClientListView()
                        .onTapGesture {
                            selectedIndex = 0
                        }
                        .tabItem {
                            Label("Clients", systemImage: "list.bullet")
                        }.tag(0)
                    ProjectListView()
                        .onTapGesture {
                            selectedIndex = 1
                        }
                        .tabItem {
                            Image(systemName: "person")
                            Label("Projects", systemImage: "list.dash")
                        }.tag(1)
                    TaskListView()
                        .tabItem {
                            Image(systemName: "person")
                            Label("Tasks", systemImage: "list.dash")
                        }.tag(2)
                    
                        .onTapGesture {
                            selectedIndex = 2
                        }
                    ClientListView()
                        .tabItem {
                            Label("Settings", systemImage: "gear")
                        }.tag(3)
                        .onTapGesture {
                            selectedIndex = 3
                        }
                }
                
                .navigationTitle(tabTitle)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Image("logo_silueta")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 30, height: 30)
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        viewModel.signOut()
                    }, label: {
                        Text("logout")
                    })
                    
                }
            }
            .navigationBarTitleDisplayMode(.inline)
        }
        
    }
    var tabTitle: String {
        switch selectedIndex {
        case 0: return "Clients"
        case 1: return "Projects"
        case 2: return "Tasks"
        case 3: return "Settings"
        default: return ""
        }
    
    }
    
}

struct MainTabView_Previews: PreviewProvider {
    static var previews: some View {
        MainTabView(selectedIndex: .constant(0))
    }
}

Navigation on the tabbed view works and displays the different names on the tab bar title, but when I click cancel or x button of the search bar, it doesn't work and also the list becomes unclickable

So far I haven't been able to find where the problem is but I am assuming its because the tab bar view is messing up with the searchable property

1
  • 1
    A NavigationView should not exist above a TabVies. Each tab can have its own . Commented Nov 16, 2022 at 10:26

2 Answers 2

0

The culprit would seem to be your .onTapGesture modifiers, which will take precedence over any tap handling in your child views.

I'm not sure what value those modifiers bring, since using appropriate .tag values is enough for the tab view to keep track of its selected index. I'd start by removing them.

6
  • Thank you @ScottM that solved the problem, yayyy. The issue now is how do I keep track of the number of the pressed tab button? I need that for other operations on the behavior of the user interface. Thank you for your help!! Commented Nov 16, 2022 at 10:36
  • selectedIndex will be updated automatically with the values that you've added via the .tag() modifiers – can you not use that?
    – ScottM
    Commented Nov 16, 2022 at 10:45
  • Also, you can move the navigationTitle declaration into each child view, and SwiftUI will handle it for you automatically. Especially if you remove the extraneous VStack and NavigationView from around the tab view, which should really be at the top level.
    – ScottM
    Commented Nov 16, 2022 at 10:47
  • Duh! sorry, most likely yes. Will let you know. Again, thanks a lot! Commented Nov 16, 2022 at 10:47
  • ScottM, got everything working and squared up, thanks again! Commented Nov 18, 2022 at 10:29
0

@ObservedObject var viewModel = ClientFeedViewModel() is a memory leak, try changing it to something like:

struct ClientListViewData {
    var searchText: String = ""
    var showingSheet = false
    var showList = false

    mutating func showSheet() {
        showingSheet = true
    }
}

struct ClientListView: View {
    @Binding var data: ClientListViewData

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.