SwiftUI 键盘关闭问题

Posted

技术标签:

【中文标题】SwiftUI 键盘关闭问题【英文标题】:SwiftUI Keyboard Dismissing Issues 【发布时间】:2021-10-04 10:10:16 【问题描述】:

目标是能够在点击屏幕上的任意位置时关闭键盘。我现在尝试了两种方法,每种方法都有不同的问题。

方法一

选取一个给定的屏幕,然后用一个点击手势将其包裹起来:

struct ContentView: View 
    
    @State private var favoriteColor = 0
    @State private var text1:String = ""
    @State private var text2:String = ""
    
    var body: some View 
        
        VStack 
            
            TextField("Type Things", text: $text1)
            
            TextField("Type More Things", text: $text2)
            
            Picker("What is your favorite color?", selection: $favoriteColor) 
                Text("Red").tag(0)
                Text("Green").tag(1)
            
            .pickerStyle(.segmented)

        
        .frame(
              minWidth: 0,
              maxWidth: .infinity,
              minHeight: 0,
              maxHeight: .infinity,
              alignment: .center
        )
        .background(Color.blue.opacity(0.4))
        .onTapGesture 
            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        
        
    

问题: 轻击手势适用于除分段控制之外的所有控件。当您按下给定的分段选项时,分段轻击手势似乎不会将控件移动到所选选项。在我看来,这似乎是一个 SwiftUI 错误。我尝试了.simultaneousGesture(TapGesture().onEnded )的各种排列方式

Picker("What is your favorite color?", selection: $favoriteColor) 
    Text("Red").tag(0)
    Text("Green").tag(1)

.pickerStyle(.segmented)
.simultaneousGesture(TapGesture().onEnded  )

.highPriorityGesture(TapGesture().onEnded )

Picker("What is your favorite color?", selection: $favoriteColor) 
    Text("Red").tag(0)
    Text("Green").tag(1)

.pickerStyle(.segmented)
.highPriorityGesture(TapGesture().onEnded  )

在最后的 hack 中,我确实尝试了以下操作。它有点工作。它只是不像一个适当的分段控件:

Picker("What is your favorite color?", selection: $favoriteColor) 
    Text("Red").tag(0)
    Text("Green").tag(1)

.pickerStyle(.segmented)
.onTapGesture 
    if self.favoriteColor == 0 
        self.favoriteColor = 1
     else 
        self.favoriteColor = 0
    

接近二

鉴于 seg 的问题,然后我选择了选项 2 并将 UIKit 轻击手势应用于窗口,如下所示:

struct ContentView: View 

    @State private var favoriteColor = 0
    @State private var text1:String = ""
    @State private var text2:String = ""
    
    var body: some View 
        
        VStack 
            
            TextField("Type Things", text: $text1)
            
            TextField("Type More Things", text: $text2)
            
            Picker("What is your favorite color?", selection: $favoriteColor) 
                Text("Red").tag(0)
                Text("Green").tag(1)
            
            .pickerStyle(.segmented)

        
        .frame(
              minWidth: 0,
              maxWidth: .infinity,
              minHeight: 0,
              maxHeight: .infinity,
              alignment: .center
        )
        .background(Color.blue.opacity(0.4))

        
    


extension UIApplication 
    func dismissKeyboardGestureRecognizer() 
        guard let window = windows.first else  return 
        let gesture = UITapGestureRecognizer(target: window, action: nil)
        gesture.requiresExclusiveTouchType = false
        gesture.cancelsTouchesInView = false
        gesture.delegate = self
        window.addGestureRecognizer(gesture)
    


extension UIApplication: UIGestureRecognizerDelegate 
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool 
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        return true
    

    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool 
        return true
    


@main
struct SeggyApp: App 
    var body: some Scene 
        WindowGroup 
            ContentView()
                .onAppear 
                    UIApplication.shared.dismissKeyboardGestureRecognizer()
                
        
    

问题: 使用这种方法,分段控制起作用。但是,如果您从一个文本字段点击到另一个,您会发现键盘上下弹跳。这是因为窗口手势检测到点击并尝试关闭键盘,然后其他文本字段注册为第一响应者,然后将键盘抬起并因此弹跳。

唉,这种弹跳是不需要的。使用方法一,这不会发生。我有点卡在岩石和坚硬的地方之间。任何人都知道如何让分段控件响应方法 1 或停止方法 2 中的弹跳键盘?

我个人认为方法一应该可行,分段控件有错误,应该报告给 Apple。

【问题讨论】:

我建议将点击手势放在背景视图而不是全部视图上 【参考方案1】:

只需将点击手势应用于背景。现在您可以通过点击蓝色背景关闭任何内容:

struct ContentView: View 
    @State private var favoriteColor = 0
    @State private var text1: String = ""
    @State private var text2: String = ""

    var body: some View 
        VStack 
            TextField("Type Things", text: $text1)

            TextField("Type More Things", text: $text2)

            Picker("What is your favorite color?", selection: $favoriteColor) 
                Text("Red").tag(0)
                Text("Green").tag(1)
            
            .pickerStyle(.segmented)
        
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(
            Color.blue
                .opacity(0.4)
                .onTapGesture 
                    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
                
        )
    

结果:

【讨论】:

以上是关于SwiftUI 键盘关闭问题的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 显示/关闭键盘

在 SwiftUI 中显示键盘上方的视图 [关闭]

如何像 SwiftUI 中的 WhatsApp 一样在滑动时关闭键盘

键盘关闭时的 SwiftUI 按钮故障

按返回键“不”关闭软件键盘 - SwiftUI

有啥方法可以在 SwiftUI 中的可搜索导航修饰符上关闭自动更正/设置键盘类型