swiftswiftuiswiftui-navigationstackswiftui-buttonswiftui-searchable

Connecting a button to .searchable modifier


I have an app with SampleData of country names displayed in a list with the searchable modifier. I also have button on the bottom right of the screen. This is all within the NavigationStack:

NavigationStack {
    VStack {
        List {
            ForEach(countries, id: \.self) { country in
                HStack { 
                    // Go through my SampleData
                }
            }
        }
        .searchable(text: $searchViewModel.searchText)
        .navigationTitle("Home")
        .overlay {
            VStack {
                Spacer()
                HStack {
                    Spacer()
                    MyButton {}
                }
            }
        }

Is there a way to "connect" MyButton to that SampleData so that when I click the button, it opens the search bar?

I've tried the property wrapper @FocusedState isSearchFocused of boolean type, and then just setting it to true when the button is pressed, but it still doesn't do anything:

// 
// Within MyButton struct
// 
var body : some View {
    Button(action: action) { 
        // button ui
    }
    .gesture(DragGesture(minimumDistance: 0)
        .onChanged { _ in
            if !isPressed {
                isPressed = true
                hapticFeedback()
                isSearchFocused = true  // this does nothing...
            }
        }
        .onEnded { _ in
            isPressed = false
            action()
            hapticFeedback()
        }
    )
}

If this is not possible, I'm assuming you need to design a custom search bar and work on it from there. It's just that the default system .searchable looks cool to me :)


Solution

  • You can pass an additional isPresented: parameter to searchable, to programmatically control whether the search bar is active:

    @State var searchText = ""
    @State var searchActive = false
    var body: some View {
        NavigationStack {
            List {
                Text("Foo")
                Text("Bar")
                Text("Baz")
            }
            .searchable(text: $searchText, isPresented: $searchActive)
            .overlay(alignment: .bottomTrailing) {
                Button {
                    searchActive = true
                } label: {
                    Image(systemName: "magnifyingglass")
                }
                .buttonStyle(.borderedProminent)
                .padding()
            }
        }
    }