TextField всегда на верхней части клавиатуры с SwiftUI
У меня есть это
struct ContentView: View {
var body: some View {
ZStack(alignment: Alignment.bottom) {
List {
Text("Default text").foregroundColor(Color.red)
}
TextField("Placeholder", text: .constant(""))
.frame(minHeight: 30)
.cornerRadius(8.0)
.padding(10)
.background(Color.blue)
}
}
}
На самом деле, когда я фокусируюсь на TextField, клавиатура скрывает это текстовое поле.
https://i.s tack.imgur.com/FULivm.png https://i.s tack.imgur.com/6VGzqm.png
Есть ли простое решение в SwiftUI, чтобы текстовое поле всегда было над клавиатурой?
2 ответа
Вот фрагмент, который наблюдает NotificationCenter
уведомления, относящиеся к клавиатуре, и изменяющие высоту вида спейсера на основе вычисленной высоты клавиатуры.
import Combine
struct ExampleView: View {
@State var keyboardHeight: CGFloat = 0
var cancellables: Set<AnyCancellable> = []
init() {
NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)
.merge(with: NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification))
.compactMap({ notification in
guard let keyboardFrameValue: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return nil }
let keyboardFrame = keyboardFrameValue.cgRectValue
// If the rectangle is at the bottom of the screen, set the height to 0.
if keyboardFrame.origin.y == UIScreen.main.bounds.height {
return 0
} else {
// Adjust for safe area
return keyboardFrame.height - (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0)
}
})
.assign(to: \.keyboardHeight, on: self)
.store(in: &cancellables)
}
var body: some View {
VStack {
// Your content here
Spacer()
.frame(height: keyboardHeight)
}
}
}
Я написал пакет Swift, который обрабатывает это для вас. Это подвергает KeyboardObservingView
это оборачивает ваш контент.
Это доступно здесь: https://github.com/nickffox/KeyboardObserving
Вы бы использовали это так:
var body: some View {
KeyboardObservingView {
List {...}
TextField("Placeholder", text: .constant(""))
.frame(minHeight: 30)
.cornerRadius(8.0)
.padding(10)
.background(Color.blue)
}
}
Вот изображение используемого пакета: демо
Я пробовал разные подходы, и ни один из них не помог мне. Этот ниже единственный, который работал на разных устройствах.
Добавьте это расширение в файл:
import SwiftUI
import Combine
extension View {
func keyboardSensible(_ offsetValue: Binding<CGFloat>) -> some View {
return self
.padding(.bottom, offsetValue.wrappedValue)
.animation(.spring())
.onAppear {
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notification in
let keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
let bottom = keyWindow?.safeAreaInsets.bottom ?? 0
let value = notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
let height = value.height
offsetValue.wrappedValue = height - bottom
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in
offsetValue.wrappedValue = 0
}
}
}
}
На ваш взгляд, вам нужна переменная для привязки offsetValue:
struct IncomeView: View {
@State private var offsetValue: CGFloat = 0.0
var body: some View {
VStack {
//...
}
.keyboardSensible($offsetValue)
}
}
Я не уверен на 100% в SwiftUI, но у меня есть вид прокрутки, и я использую эту функцию, чтобы мое текстовое поле и кнопка всегда были над клавиатурой
//function for scroll view to adjust when is keyboard is appeared so the text field stays above the keyboard
@objc func adjustForKeyboard(notification: Notification) {
guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardScreenEndFrame = keyboardValue.cgRectValue
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
if notification.name == UIResponder.keyboardWillHideNotification {
scrollView.contentInset = .zero
} else {
if #available(iOS 11.0, *) {
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height - view.safeAreaInsets.bottom, right: 0)
}
}
scrollView.scrollIndicatorInsets = scrollView.contentInset
}
Вы можете использовать это, вызывая так с UIResponder и селектором на вашем viewDidLoad.
//register for keyboard change notifications when text field is being used
NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
Просто собираюсь предложить простое, легкое и немного хакерское решение, которое я нашел для работы с клавиатурой:
struct ContentView : View {
@State private var name = ""
@State private var keyboardUp = false
private var keyboardHeight: CGFloat { 150 }
var body: some View {
NavigationView {
Spacer()
Form {
TextField($name, placeholder: Text("Name"), onEditingChanged: { { self.keyboardUp = $0 })
}.offset(y: keyboardUp ? -keyboardHeight : 0)
.animation(.basic())
.navigationBarTitle(Text("Title"))
}
}
}