SwiftUI - 滚动时关闭键盘

Dan*_*zer 10 ios swiftui

我有一个简单的搜索列表:


struct ContentView: View {
    @State var text:String = ""
    var items = 1...100
    var body: some View {
        VStack {
            List {
                TextField("Search", text: $text)
                Section{
                    ForEach(items.filter({"\($0)".contains(text)}),id: \.self){(i) in
                       Text("option \(i)")
                    }
                }
            }
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

iOS模拟器截图

滚动超过 2 个单元格/几个点时如何关闭键盘?

vau*_*all 15

如果您正在使用 a ScrollView(可能也使用 a,List但我尚未确认),您可以使用UIScrollView appearance,但这会影响所有 ScrollView。

UIScrollView.appearance().keyboardDismissMode = .onDrag
Run Code Online (Sandbox Code Playgroud)

  • 我发现,如果显示表情符号键盘并且您滑动表情符号,这会导致键盘奇怪地隐藏 - 关于如何解决这个问题有什么想法吗? (6认同)
  • 仅当您没有任何滚动的文本编辑器或文本视图时才使用此选项,因为它们也会受到此通用配置的影响 (2认同)

use*_*284 11

对于这个问题,可以找到关于如何放弃键盘的深入讨论,并提供各种答案。

在列表中的拖动手势上放弃键盘的一种解决方案是使用 UIApplication 窗口上的方法,如下所示。为了更容易处理,我在 UIApplication 上创建了一个扩展,并为此扩展创建了视图修饰符,最后创建了 View 的扩展:

extension UIApplication {
    func endEditing(_ force: Bool) {
        self.windows
            .filter{$0.isKeyWindow}
            .first?
            .endEditing(force)
    }
}

struct ResignKeyboardOnDragGesture: ViewModifier {
    var gesture = DragGesture().onChanged{_ in
        UIApplication.shared.endEditing(true)
    }
    func body(content: Content) -> some View {
        content.gesture(gesture)
    }
}

extension View {
    func resignKeyboardOnDragGesture() -> some View {
        return modifier(ResignKeyboardOnDragGesture())
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,放弃键盘的最后一个修饰符只是一个必须放在列表中的修饰符,如下所示:

List {
    ForEach(...) {
        //...
    }
}
.resignKeyboardOnDragGesture()
Run Code Online (Sandbox Code Playgroud)

我还实现了一个纯 swiftUI 版本的搜索栏,您可能会感兴趣。你可以在这个答案中找到它。


小智 11

就目前而言,自 iOS 16 beta 以来,我们有了一个新的修改器scrollDismissesKeyboard(),可以完全满足您的需求。

\n

在你的例子中它应该看起来像

\n
struct ContentView: View {\n    @State var text: String = ""\n    var items = 1...100\n    var body: some View {\n        List {\n            TextField("Search", text: $text)\n            Section {\n                ForEach(items.filter({"\\($0)".contains(text)}), id: \\.self) { (i) in\n                    Text("option \\(i)")\n                }\n            }\n        }\n        .scrollDismissesKeyboard(.interactively) // <<-- Put this line\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

修饰符scrollDismissesKeyboard()有一个参数确定驳回规则。以下是可能的值:

\n
    \n
  • .automatic:根据卷轴的上下文消除。
  • \n
  • .immediately:一旦发生任何滚动,键盘就会消失。
  • \n
  • .interactively:键盘将随着用户\xe2\x80\x99s 手势移动/消失。
  • \n
  • .never:当用户滚动时,键盘永远不会消失。
  • \n
\n


Seu*_*Ham 7

Form {
    ...
}.gesture(DragGesture().onChanged { _ in
    UIApplication.shared.windows.forEach { $0.endEditing(false) }
})
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,我发现这会干扰滑动删除。 (3认同)

Pau*_*l B 5

@FocusState包装器和.focused() TextField修饰符可能很有用。

struct ContentView: View {
    @FocusState private var focusedSearchField: Bool
    @State var text:String = ""
    var items = 1...100
    var body: some View {
        VStack {
            List {
                TextField("Search", text: $text)
                    .focused($focusedSearchField)
                Section{
                    ForEach(items.filter({"\($0)".contains(text)}),id: \.self){(i) in
                        Text("option \(i)")
                    }
                }
            } // to also allow swipes on items (theoretically)
            .simultaneousGesture(DragGesture().onChanged({ _ in
                focusedSearchField = false
            }))
            .onTapGesture { // dissmis on tap as well
                focusedSearchField = false
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)