Search code examples
swiftuicustom-keyboard

How can I dismiss the keyboard, and have a new view behind it, while keeping the .toolbar visable in SwiftUI?


I am looking to be able to click a button, which dismisses the keyboard, and replace the keyboard space with a new view. Notion has this functionality in their app. I've attached a gif for clarity on what functionality I'm trying to achieve.

demo


Solution

  • You can get the height of the keyboard with

    .onReceive(NotificationCenter
        .default
        .publisher(for: UIResponder.keyboardWillShowNotification)
        .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue }
        .map { $0.cgRectValue.height }, perform: { height in
            self.height = height //Adjust the height based on the keyboard
    })
    

    Then bring the keyboard in/out by setting

    @FocusState var isFocused: Bool
    

    to true/false

    Here is a full sample.

    import SwiftUI
    
    struct KeyboardHeightView: View {
        //Use this to bring/dismiss keyboard
        @FocusState var isFocused: Bool
        @State private var height: CGFloat = 300
        @State private var text: String = "test"
        @ScaledMetric var buttonHeight = 40
        var body: some View {
            VStack{
                TextEditor(text: $text)
                    .focused($isFocused)
                //Parent for buttons and actions
                Rectangle()
                    .fill(Color.white)
                    .border(Color.green)
                    .overlay {
                        //Area for buttons and actions
                        VStack {
                            //Space for the buttons
                            HStack{
                                Text("tap to dismiss")
                                    .onTapGesture {
                                        isFocused = false //Dismiss Keyboard
                                    }
                            }
                            .frame(height: buttonHeight)
                            .frame(maxWidth: .infinity)
                            .border(Color.red)
                            //Space for other actions.
                            Button("perform some action") {
                                //Do something
                                isFocused = true //Show the  keyboard again.
                            }
                            Spacer()
                        }
                    }
                    .frame(height: height + buttonHeight) //Keyboard + the space for the buttons that dismiss keyboard and show actions
            }.ignoresSafeArea(.keyboard)
                .edgesIgnoringSafeArea(.bottom)
                .onReceive(NotificationCenter
                    .default
                    .publisher(for: UIResponder.keyboardWillShowNotification)
                    .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue }
                    .map { $0.cgRectValue.height }, perform: { height in
                        self.height = height //Adjust the height based on the keyboard
                    })
                .task {
                    isFocused = true //Show keyboard when the View appears
                }
        }
    }
    
    #Preview {
        KeyboardHeightView()
    }