iOS14中的SwiftUI键盘避免问题和IgnoreSaareA修改器问题

iOS14中的SwiftUI键盘避免问题和IgnoreSaareA修改器问题,ios,swiftui,Ios,Swiftui,iOS13发现TextField没有任何类型的键盘避免处理。因此,我们创建了如何避免键盘的机制,该机制运行良好。我们升级到iOS14,这导致文本字段内置键盘避免功能。然而,避免使用键盘似乎并不像预期的那样有效 第1期 我们遇到的第一个问题是键盘避免功能无法正常工作,屏幕中心及其周围的文本字段也无法正常工作。鉴于此代码: struct ContentView: View { @State var text:String = "" var bo

iOS13发现TextField没有任何类型的键盘避免处理。因此,我们创建了如何避免键盘的机制,该机制运行良好。我们升级到iOS14,这导致文本字段内置键盘避免功能。然而,避免使用键盘似乎并不像预期的那样有效

第1期 我们遇到的第一个问题是键盘避免功能无法正常工作,屏幕中心及其周围的文本字段也无法正常工作。鉴于此代码:

struct ContentView: View {
    
    @State var text:String = ""
    
    var body: some View {
        
        TextField("Testing", text: $text)

    }
}
在iPhone和iPhone8 Plus上,文本字段向上移动。在我们看来,这不应该发生,因为文本字段不会被键盘隐藏,因此它应该保持在相同的位置

问题1: 这是一个bug,应该向苹果报告吗?我们认为这是一个错误/问题

我们发现,使用以下方法:

struct ContentView: View {
    
    @State var text:String = ""
    
    var body: some View {
        
        VStack {
            Spacer()
            TextField("Testing", text: $text)
        }
        
    }
}
文本字段将移动到键盘的正上方。这是预期的行为。我们还发现,使用以下代码:

struct ContentView: View {
    
    @State var text:String = ""
    
    var body: some View {
        
        VStack {
            TextField("Testing", text: $text)
            Spacer()
        }
        
    }
}
TextField不会移动,因为它永远不会被TextField覆盖。这也是我们所期望的行为。然而,任何位于屏幕中心及其周围的文本字段,似乎键盘回避会将文本字段移动到场景中不应该移动的位置

第二期 我们的应用程序在某些屏幕上的中心及其周围保留文本字段,因此,上面发现的问题只会增加糟糕的用户体验,因此我们希望“关闭”提供给我们的这个键盘避免功能。我们希望使用
ignoresSafeArea
修饰符,如下所示:

struct ContentView: View {
    
    @State var text:String = ""
    
    var body: some View {

        if #available(iOS 14.0, *) {
            
            VStack {
                TextField("Testing", text: $text)
            }
            .ignoresSafeArea(.keyboard, edges: .bottom)

            
        } else {
            // Fallback on earlier versions
            // Our iOS13 Code
        }
                
    }
}
观察到的结果是修改器根本不起作用。文本字段仍向上移动。但是,当使用类似的方法时:

struct ContentView: View {
    
    @State var text:String = ""
    
    var body: some View {

        if #available(iOS 14.0, *) {
            
            VStack {
                Spacer()
                TextField("Testing", text: $text)
            }
            .ignoresSafeArea(.keyboard, edges: .bottom)

            
        } else {
            // Fallback on earlier versions
            // Our iOS13 Code
        }
                
    }
}
ignoresSafeArea
起作用,因此引出第二个问题:

问题2
ignoresSafeArea
修饰符是否也存在bug?这是应该报告的事情吗

在屏幕中央及其周围的文本字段似乎存在一个潜在问题

问题3 有人知道解决这些问题的方法吗?因为现在在iOS14上是个大问题。键盘回避不起作用,任何试图关闭键盘的尝试也不起作用

我们使用的是Xcode 12.0(12A7209)

更新

我们发现,在几何体读取器中包装文本字段似乎可以“关闭”文本字段的键盘回避。然而,我们认为这是一个令人愉快的黑客行为,它以一种方式修复了问题,但同时也暴露出键盘回避在几何体阅读器中不起作用,这可能是其他人的一个bug/问题

struct ContentView: View {
    
    @State var text:String = ""
    
    var body: some View {

        if #available(iOS 14.0, *) {
            
            GeometryReader { _ in
                VStack {
                    Spacer().frame(height:500) //Compensate for other Views in the Stack
                    TextField("Testing", text: $text)
                }
            }
            
        } else {
            // Fallback on earlier versions
            // Our iOS13 Code
        }
                
    }
}

在这里,您可以看到我根据您的GeometryReader hack得出的结论:

您描述的行为都是预期的。我们需要了解三件事:

  • 快捷布局系统
  • 键盘安全区
  • 无知者恐惧
  • (1) SwiftUI布局系统中最相关的概念是视图可以具有固定大小或灵活大小。例如,单行文本具有固定大小。因此,只有文本的VStack也有固定的大小。试试这个

    struct ContentView: View {
        var body: some View {
            VStack {
                Text("Hello")
                Text("World")
            }
            .border(Color.green)
        }
    }
    
    您可以看到绿色边框仅环绕文本

    另一方面,
    Spacer
    s、
    Color
    s、
    GeometryReader
    s等具有灵活的尺寸,它们往往会扩展以占据所有可用空间

    (2) 显示键盘时,容器上有一个安全区域。容器的高度将降低

    (3) IGNORESSAFEREA修改器通常应用于具有灵活高度的视图。以底部边缘为例,仅当视图的原始底部边缘与底部安全区域的顶部边缘对齐或被底部安全区域覆盖时,修改器才会产生效果。因此,如果视图的底部边缘远离底部安全区域的顶部边缘,则IgnoreSaareA将不起作用

    现在,我将解释为什么您所有的示例都具有预期的行为

    例1

    struct ContentView: View {
    
        @State var text: String = ""
    
        var body: some View {
    
            TextField("Testing", text: $text)
    
        }
    }
    
    行为:即使未被键盘覆盖,当键盘显示时,文本字段也会稍微向上移动

    原因:安全区域在容器上,当键盘显示时,容器的高度降低。由于文本字段位于容器的中心,因此它会向上移动一点

    例2

    struct ContentView: View {
    
        @State var text: String = ""
    
        var body: some View {
    
            VStack {
                Spacer()
                TextField("Testing", text: $text)
            }
    
        }
    }
    
    行为:当键盘显示时,文本字段正好移动到键盘上方

    原因:VStack中有一个垫片,因此VStack将一直延伸到容器提供的高度。当容器的高度因键盘而降低时,VStack的高度也会降低

    例3

    struct ContentView: View {
    
        @State var text: String = ""
    
        var body: some View {
            VStack {
                TextField("Testing", text: $text)
            }
            .ignoresSafeArea(.keyboard, edges: .bottom)
        }
    }
    
    行为:当键盘显示时,文本字段稍微向上移动。ignoresSafeArea修改器没有任何效果

    原因:在VStack上应用ignoresSafeArea,而VStack有固定的高度,且其底边远离底部安全区域,ignoresSafeArea无效。但容器并不忽略SSAFEREA,因此当键盘显示时,容器的高度仍然会降低

    例4

    struct ContentView: View {
    
        @State var text: String = ""
    
        var body: some View {
            VStack {
                Spacer()
                TextField("Testing", text: $text)
            }
            .ignoresSafeArea(.keyboard, edges: .bottom)
        }
    }
    
    行为:当键盘显示IgnoreSaareA正在工作时,文本字段不移动

    原因:这次垫片将使VStack延伸其高度。请记住,容器不会忽略IgnoreSaareA,因此如果未应用IgnoreSaareA修改器,当键盘显示时,VStack的下边缘将刚好与底部安全区域的上边缘对齐。因此,这一次如果应用ignoresSafeArea,它将起作用,并使VStack扩展其高度以忽略键盘底部的安全区域

    另一个示例可以帮助您理解父视图如何尊重安全区域,而子视图如何忽略它们

    struct ContentView: View {
        var body: some View {
            ZStack {
                Color.yellow
                Color.green
                    .frame(width: 200)
                    .ignoresSafeArea()
            }
            .border(Color.blue, width: 10)
        }
    }
    
    struct ContentView: View {
    
        @State var text: String = ""
    
        var body: some View {
            ZStack {
                Color.clear
                VStack {
                    TextField("Testing", text: $text)
                }
            }
            .ignoresSafeArea(.keyboard)
        }
    }