Отклонение клавиатуры при нажатии в любом месте (как предлагали другие) может привести к очень трудным для поиска ошибкам (или нежелательному поведению).
- вы теряете встроенное поведение TextField по умолчанию, например частичное выделение текста, копирование, совместное использование и т. д. c.
- onCommit не называется
Я предлагаю вам подумать о маскировании жестов на основе состояния редактирования ваших полей
/// Attaches `gesture` to `self` such that it has lower precedence
/// than gestures defined by `self`.
public func gesture<T>(_ gesture: T, including mask: GestureMask = .all) -> some View where T : Gesture
это поможет нам написать
.gesture(TapGesture().onEnded({
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}), including: (editingFlag) ? .all : .none)
Нажмите на измененный вид, чтобы закрыть клавиатуру, но только если editingFlag == true
. Не применять его на TextField! В противном случае мы снова в начале истории: -)
Этот модификатор поможет нам решить проблему с Picker
, но не с Button
. Это легко решить, пока клавиатура не отключается от собственного обработчика действий. У нас нет никаких других элементов управления, поэтому мы почти закончили
Наконец, мы должны найти решение для остальной части View, поэтому нажатие в любом месте (исключая наши текстовые поля) отклоняет клавиатуру . Использование ZStack
, заполненного прозрачным представлением, вероятно, самое простое решение.
Давайте посмотрим на все это в действии (копировать - вставить - запустить в симуляторе Xcode)
import SwiftUI
struct ContentView: View {
@State var selected = 0
@State var textFieldValue0 = ""
@State var textFieldValue1 = ""
@State var editingFlag = false
@State var message = ""
var body: some View {
ZStack {
// TODO: make it Color.clear istead yellow
Color.yellow.opacity(0.1).onTapGesture {
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}
VStack {
TextField("Salutation", text: $textFieldValue0, onEditingChanged: { editing in
self.editingFlag = editing
}, onCommit: {
self.onCommit(txt: "salutation commit")
})
.padding()
.background(Color(UIColor.secondarySystemFill))
.cornerRadius(4)
TextField("Welcome message", text: $textFieldValue1, onEditingChanged: { editing in
self.editingFlag = editing
}, onCommit: {
self.onCommit(txt: "message commit")
})
.padding()
.background(Color(UIColor.secondarySystemFill))
.cornerRadius(4)
Picker(selection: $selected, label: Text(""), content: {
Text("Word").tag(0)
Text("Phrase").tag(1)
Text("Sentence").tag(2)
})
.pickerStyle(SegmentedPickerStyle())
.gesture(TapGesture().onEnded({
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}), including: (editingFlag) ? .all : .none)
Button(action: {
self.textFieldValue0 = "Hi"
print("button pressed")
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}, label: {
Text("Tap to change salutation")
.padding()
.background(Color.yellow)
.cornerRadius(10)
})
Text(textFieldValue0)
Text(textFieldValue1)
Text(message).font(.largeTitle).foregroundColor(Color.red)
}
}
}
func onCommit(txt: String) {
print(txt)
self.message = [self.textFieldValue0, self.textFieldValue1].joined(separator: ", ").appending("!")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Если вы пропустите onCommit (он не вызывается при нажатии вне TextField), просто добавьте его в TextField onEditingChanged
(он имитирует ввод на клавиатуре)
TextField("Salutation", text: $textFieldValue0, onEditingChanged: { editing in
self.editingFlag = editing
if !editing {
self.onCommit(txt: "salutation")
}
}, onCommit: {
self.onCommit(txt: "salutation commit")
})
.padding()
.background(Color(UIColor.secondarySystemFill))
.cornerRadius(4)