The current implementation will only update the padding if the keyboard shows or hides. But what if the view re-renders, moving the first responder up or down, while the keyboard is showing?
This happens in my app, which is a tutorial for setting up a custom keyboard. My view is like this:
struct SwitchToKeyboardView: View {
@EnvironmentObject var keyboardState: KeyboardState
@State var dummyText = ""
@State var dummyInputIsEditing = true
@ViewBuilder
var body: some View {
VStack {
if keyboardState.hasBeenOpened {
Text("Great!").font(.title)
Text("Searchboard is now ready")
Text("to use in any app.")
} else {
Text("Tap and hold the ") + Text("Globe").bold() + Text(" icon")
Text("Tap ") + Text("Searchboard").bold() + Text(" to switch keyboards")
}
// Use an invisible text view to bring up the keyboard and to
// permit the keyboard to tell us that we're opened (see
// `KeyboardState`). We don't use a text field since you can't
// force those to become first responder
// https://stackoverflow.com/a/56508132/495611 . Keep the text
// view visible even after the user has switched, the first
// time that they switch, so that they can play around with the
// keyboard.
TextView(text: $dummyText, isEditing: $dummyInputIsEditing).frame(width: 0, height: 0, alignment: .center)
}
.keyboardAdaptive()
}
}
Where TextView is an instance of this. I won't get into the implementation of KeyboardState unless you like, but I have a mechanism where once my custom keyboard opens, it causes keyboardState.hasBeenOpened to become true, asynchronously with respect to the keyboard changing.
You may notice that the text above the field grows bigger when the keyboard has been opened, so the padding needs to increase. But it doesn't, because the update comes in after the keyboard has already changed.
Here's a PR that's a stab at re-rendering the ViewModifier when the keyboard height changes or when a client-provided publisher fires. In my case, that publisher is a binding to keyboardState.hasBeenOpened: I change my .keyboardAdaptive() invocation to look like
.keyboardAdaptive(rerender: keyboardState.$hasBeenOpened.map({ arg -> Any in
arg
}).eraseToAnyPublisher())
There are a bunch of things I don't like about this approach, but I figured I'd put it up to start a conversation.
The current implementation will only update the padding if the keyboard shows or hides. But what if the view re-renders, moving the first responder up or down, while the keyboard is showing?
This happens in my app, which is a tutorial for setting up a custom keyboard. My view is like this:
Where
TextView
is an instance of this. I won't get into the implementation ofKeyboardState
unless you like, but I have a mechanism where once my custom keyboard opens, it causeskeyboardState.hasBeenOpened
to becometrue
, asynchronously with respect to the keyboard changing.You may notice that the text above the field grows bigger when the keyboard has been opened, so the padding needs to increase. But it doesn't, because the update comes in after the keyboard has already changed.
Here's a PR that's a stab at re-rendering the
ViewModifier
when the keyboard height changes or when a client-provided publisher fires. In my case, that publisher is a binding tokeyboardState.hasBeenOpened
: I change my.keyboardAdaptive()
invocation to look likeThere are a bunch of things I don't like about this approach, but I figured I'd put it up to start a conversation.