Reputation: 4300
I have a SwiftUI application with SwiftUI lifecycle that uses TextFields and TextEditors. I have written a modifier to deal with scrolling the content that would be underneath the keyboard when the keyboard is present. My modifier works as expected for TextFields but not at all for TextEditors. The Apple docs say the keyboardWillShowNotification is posted immediately prior to the display of the keyboard. I cannot find anything which states the notification is limited to only TextFields. Both field types are in the same ScrollView. Hopefully I'm missing something simple here.
My modifier:
struct AdaptsToSoftwareKeyboard: ViewModifier {
@State var currentHeight: CGFloat = 0
func body(content: Content) -> some View {
content
.padding(.bottom, self.currentHeight)
.edgesIgnoringSafeArea(self.currentHeight == 0 ? Edge.Set() : .bottom)
.onAppear(perform: subscribeToKeyboardEvents)
}
private let keyboardWillOpen = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { $0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect }
.map { $0.height }
private let keyboardWillHide = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat.zero }
private func subscribeToKeyboardEvents() {
_ = Publishers.Merge(keyboardWillOpen, keyboardWillHide)
.subscribe(on: RunLoop.main)
.assign(to: \.self.currentHeight, on: self)
}
}
Any guidance would be appreciated. Xcode Version 12.2 beta (12B5018i) iOS 14
First edit: I thought the issue was likely a failure to receive notifications when the TextEditor receives the focus. However, adding this modifier to the TextEditor shows that the notification is fired. No progress:
.onReceive(NotificationCenter.default.publisher(for: UIApplication.keyboardWillShowNotification)) { _ in
print("Cursor is in TextEditor!")
}
Upvotes: 5
Views: 1481
Reputation: 257789
I assume you should store subscriber as below
struct AdaptsToSoftwareKeyboard: ViewModifier {
@State var currentHeight: CGFloat = 0
@State private var cancelable: AnyCancellable?
func body(content: Content) -> some View {
content
.padding(.bottom, self.currentHeight)
.edgesIgnoringSafeArea(self.currentHeight == 0 ? Edge.Set() : .bottom)
.onAppear(perform: subscribeToKeyboardEvents)
}
private let keyboardWillOpen = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { $0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect }
.map { $0.height }
private let keyboardWillHide = NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat.zero }
private func subscribeToKeyboardEvents() {
self.cancelable = Publishers.Merge(keyboardWillOpen, keyboardWillHide)
.subscribe(on: RunLoop.main)
.assign(to: \.self.currentHeight, on: self)
}
}
Upvotes: 3