我有一个TextField和一些可操作的元素,例如Button,Picker在视图中。当使用在TextField. 使用this question中的答案,我实现了它。然而,问题来自于其他可操作的项目。
当我点击 a 时Button,动作发生但键盘不会消失。与Toggle开关相同。当我点击 SegmentedStyle 的一个部分时Picker,键盘会关闭,但选择器选择不会改变。
这是我的代码。
struct SampleView: View {
@State var selected = 0
@State var textFieldValue = ""
var body: some View {
VStack(spacing: 16) {
TextField("Enter your name", text: $textFieldValue)
.padding(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
.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())
Button(action: {
self.textFieldValue = "button tapped"
}, label: {
Text("Tap to change text")
})
}.padding()
.onTapGesture(perform: UIApplication.dismissKeyboard)
// .gesture(TapGesture().onEnded { _ in UIApplication.dismissKeyboard()})
}
}
public extension UIApplication {
static func dismissKeyboard() {
let keyWindow = shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
keyWindow?.endEditing(true)
}
}
Run Code Online (Sandbox Code Playgroud)
正如您在代码中看到的那样,我尝试了这两个选项来获取点击手势,但没有任何效果。
通过点击任意位置关闭键盘(就像其他人建议的那样)可能会导致很难发现错误(或不需要的行为)。
我建议您根据字段的编辑状态考虑手势屏蔽
/// 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
Run Code Online (Sandbox Code Playgroud)
这有助于我们写
.gesture(TapGesture().onEnded({
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}), including: (editingFlag) ? .all : .none)
Run Code Online (Sandbox Code Playgroud)
点击修改后的视图将关闭键盘,但前提是editingFlag == true。不要将其应用到 TextField 上!否则我们又回到了故事的开始:-)
这个修饰符将帮助我们解决使用Picker而不是使用的问题Button。当将键盘从其自己的操作处理程序中关闭时,这个问题很容易解决。我们没有任何其他控件,所以我们几乎完成了
最后,我们必须找到视图其余部分的解决方案,因此点击任意位置(不包括我们的文本字段)关闭键盘。使用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()
}
}
Run Code Online (Sandbox Code Playgroud)
如果您错过了 onCommit(在点击 TextField 外部时不会调用它),只需将其添加到您的 TextField 中onEditingChanged(它模仿在键盘上键入 Return)
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)
Run Code Online (Sandbox Code Playgroud)
我想进一步采用 Mark Ts 的答案,并将整个函数添加到以下扩展中View:
extension View {
func hideKeyboardWhenTappedAround() -> some View {
return self.onTapGesture {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
to: nil, from: nil, for: nil)
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以这样调用:
var body: some View {
MyView()
// ...
.hideKeyboardWhenTappedAround()
// ...
}
Run Code Online (Sandbox Code Playgroud)
您可以像这样在 View 上创建扩展
extension View {
func endTextEditing() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
to: nil, from: nil, for: nil)
}
}
Run Code Online (Sandbox Code Playgroud)
并将其用于要关闭键盘的视图。
.onTapGesture {
self.endTextEditing()
}
Run Code Online (Sandbox Code Playgroud)
我刚刚在最近的 raywenderlich 教程中看到了这个解决方案,所以我认为它是目前最好的解决方案。