I am working on an iOS application using SwiftUI. In my app, I have a TextEditor where the user can enter text. As the user writes and the text becomes longer, the TextEditor's content moves downwards, eventually going behind the keyboard, making it hard for the user to see what they are typing.
What I want to achieve is that, when the user is typing and the cursor reaches the line just above the keyboard, the content of the TextEditor should start to scroll upwards, so that the text the user is currently writing remains visible and does not hide behind the keyboard.
Here is a simplified version of my current code:
struct NewEntryView: View {
@ObservedObject private var keyboardResponder = KeyboardResponder()
@State private var text: String = ""
var body: some View {
ScrollView {
TextEditor(text: $text)
.padding(.bottom, keyboardResponder.currentHeight)
.animation(.easeOut(duration: 0.3))
}
}
}
class KeyboardResponder: ObservableObject {
@Published var currentHeight: CGFloat = 0
var notificationCenter: NotificationCenter
init(center: NotificationCenter = .default) {
notificationCenter = center
notificationCenter.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyBoardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
currentHeight = keyboardSize.height
}
}
@objc func keyBoardWillHide(notification: Notification) {
currentHeight = 0
}
}
My question is: How can I make the TextEditor in SwiftUI automatically scroll its content upwards as the user types and the cursor reaches the line just above the keyboard, to ensure the text the user is currently writing remains visible above the keyboard?
Thank you in advance for your help!
Matt commented above some good ideas but if you're really committed to this code, I think you could use the onChange to receive the desired behavior.
Something along the lines of: