Presenting a Sheet from a Popover Will Disable the Keyboard in iOS (SwiftUI Bug)

Presenting a Sheet from a Popover Will Disable the Keyboard in iOS (SwiftUI Bug)

SwiftUI contains a bug that occurs when keyboard, popover and sheet are used in combination. This post includes a workaround until it's fixed.

·

2 min read

This is occurring as of Xcode 15.3 (15E204a) on simulator and device

There is a situation in Lyrcs where:

  1. UITextView has keyboard focus

  2. Popover appears from a button tap

  3. Sheet appears from the popover

When the user dismisses the sheet and popover, UITextView will no longer have keyboard focus but the user can no longer make the keyboard appear by tapping on the UITextView . If the user holds down on the text input then the caret appears but still no keyboard. Even when using iOS simulator, characters typed with the macOS keyboard do not appear in the text input.

This occurs with any keyboard focus element; UITextField, TextField, TextEditor etc.

This is demonstrated with the following sample code:

struct ContentView: View {
    @State private var text = ""
    @State private var isPopoverPresented: Bool = false
    @State private var isSheetPresented: Bool = false

    var body: some View {
        VStack {
            Button("Show Popover") {
                isPopoverPresented = true
            }
            .popover(isPresented: $isPopoverPresented, content: {
                Button("Show Sheet") {
                    isSheetPresented = true
                }
                    .presentationCompactAdaptation(.popover)
                    .sheet(isPresented: $isSheetPresented, content: {
                        Text("I am a sheet")
                    })
            })
            TextField("Enter text", text: $text)
        }
    }
}

Until this is fixed, Lyrcs uses the following workaround (placed on the VStack) which dismisses the keyboard when the popover is presented:

extension View {
    func workaround_dismissKeyboardWhenPopoverAppears(isPopoverPresented: Bool) -> some View {
        onChange(of: isPopoverPresented) { previous, new in
            if new, new != previous {
                UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
                                                    to: nil, from: nil, for: nil)
            }
        }
    }
}

This has been submitted to Apple (FB13802395).