How to display .toolbar on keyboard summoned by .searchable in swiftUI 3.0?

Viewed 486

I want to display segmented picker in the toolbar of a keyboard which was summoned by pressing search bar. So far my code looks like this:

import SwiftUI

struct ContentView: View {
    @State var searchText = ""
    @State var selected = false
    var body: some View {
        NavigationView{
        Text(searchText)
            .searchable(text: $searchText)
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Picker(selection: $selected, label: Text(""), content: {
                        Text("false").tag(false)
                        Text("true").tag(true)
                    }) .pickerStyle(SegmentedPickerStyle())
                }
            }
        }
    }
}

I've been able to make this toolbar work with regular textfield, and thought that using it with searchbar will be as easy, but no toolbar with textfield code:

import SwiftUI

struct ContentView: View {
    @State var textfieldText = ""
    @State var selected = false
    var body: some View {
        NavigationView{
            TextField("Textfield", text: $textfieldText)
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Picker(selection: $selected, label: Text(""), content: {
                        Text("false").tag(false)
                        Text("true").tag(true)
                    }) .pickerStyle(SegmentedPickerStyle())
                }
            }
        }
    }
}
1 Answers

ToolbarItemGroup(placement: .keyboard) does not work togther with the .searchable() view modifier.


There is an environment object called isSearching that shows whether the user is currently interacting with a search field that has been placed by a surrounding searchable modifier.

struct KeyboardToolbar<ToolbarView: View>: ViewModifier {
    @Environment(\.isSearching) var isSearching
    
    let height: CGFloat
    let toolbarView: ToolbarView
    
    init(height: CGFloat, @ViewBuilder toolbar: () -> ToolbarView) {
        self.height = height
        self.toolbarView = toolbar()
    }
    
    func body(content: Content) -> some View {
        ZStack(alignment: .bottom) {
            GeometryReader { geometry in
                VStack {
                    content
                }
                .frame(width: geometry.size.width, height: geometry.size.height)
            }
            if isSearching {
                toolbarView
                    .frame(height: self.height)
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}


extension View {
    func keyboardToolbar<ToolbarView>(height: CGFloat, view: @escaping () -> ToolbarView) -> some View where ToolbarView: View {
        modifier(KeyboardToolbar(height: height, toolbar: view))
    }
}


Use .keyboardToolbar()

struct ContentView: View {
    @State var searchText = ""
    @State var selected = false
    
    var body: some View {
        NavigationView{
            Text("Keyboar toolbar")
                .keyboardToolbar(height: 50) {
                    Picker(selection: $selected, label: Text(""), content: {
                        Text("false").tag(false)
                        Text("true").tag(true)
                    }) .pickerStyle(SegmentedPickerStyle())
                }
                .searchable(text: $searchText)
        }
    }
}

Documentation

https://developer.apple.com/documentation/swiftui/environmentvalues/issearching

Related