The following code gets the keyboard height when the keyboard is displayed and moves the button by the keyboard height.
This movement is performed in the same way at the transition source (ContentView) and the transition destination (SecibdContentView), but the button does not move at the transition destination.
How can I make the buttons move the same on multiple screens?
import SwiftUI
struct ContentView: View {
@ObservedObject private var keyboard = KeyboardResponder()
var body: some View {
NavigationView {
VStack {
Text("ContentView")
Spacer()
NavigationLink(destination: SecondContentView()) {
Text("Next")
}
.offset(x: 0, y: -keyboard.currentHeight)
}
}
}
}
import SwiftUI
struct SecondContentView: View {
@ObservedObject private var keyboard = KeyboardResponder()
var body: some View {
VStack {
Text("SubContentView")
Spacer()
NavigationLink(destination: ThirdContentView()) {
Text("Next")
}
.offset(x: 0, y: -keyboard.currentHeight)
}
}
}
class KeyboardResponder: ObservableObject {
private var _center: NotificationCenter
@Published var currentHeight: CGFloat = 0
init(center: NotificationCenter = .default) {
_center = center
_center.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
_center.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
deinit {
_center.removeObserver(self)
}
@objc func keyBoardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
currentHeight = keyboardSize.height
}
}
@objc func keyBoardWillHide(notification: Notification) {
currentHeight = 0
}
}
You can use ViewModifier of swiftui is much simpler
import SwiftUI
import Combine
struct KeyboardAwareModifier: ViewModifier {
@State private var keyboardHeight: CGFloat = 0
private var keyboardHeightPublisher: AnyPublisher<CGFloat, Never> {
Publishers.Merge(
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue }
.map { $0.cgRectValue.height },
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat(0) }
).eraseToAnyPublisher()
}
func body(content: Content) -> some View {
content
.padding(.bottom, keyboardHeight)
.onReceive(keyboardHeightPublisher) { self.keyboardHeight = $0 }
}
}
extension View {
func KeyboardAwarePadding() -> some View {
ModifiedContent(content: self, modifier: KeyboardAwareModifier())
}
}
And in your view
struct SomeView: View {
@State private var someText: String = ""
var body: some View {
VStack {
Spacer()
TextField("some text", text: $someText)
}.KeyboardAwarePadding()
}
}
KeyboardAwarePadding()
will automatically add a padding in your view, It's more elegant.
@Published var keyboardHeight: CGFloat = 0 // if one is in ViewModel: ObservableObject
private var cancellableSet: Set<AnyCancellable> = []
init() {
NotificationCenter.default.publisher(for: UIWindow.keyboardWillShowNotification)
.map {
guard
let info = $0.userInfo,
let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
else { return 0 }
return keyboardFrame.height
}
.assign(to: \.keyboardHeight, on: self)
.store(in: &cancellableSet)
NotificationCenter.default.publisher(for: UIWindow.keyboardDidHideNotification)
.map { _ in 0 }
.assign(to: \.keyboardHeight, on: self)
.store(in: &cancellableSet)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With