簡體   English   中英

iOS14 中的 SwiftUI 鍵盤回避問題和 IgnoresSafeArea 修飾符問題

[英]SwiftUI in iOS14 Keyboard Avoidance Issues and IgnoresSafeArea Modifier Issues

iOS13 發現 TextField 沒有任何類型的鍵盤避免處理。 因此,我們創建了運行良好的鍵盤避免機制。 我們升級到 iOS14,這導致 TextFields 內置了鍵盤避免功能。但是,鍵盤避免功能似乎沒有按預期工作。

問題 1我們遇到的第一個問題是鍵盤避免在屏幕中心和周圍的文本字段中無法正常工作。 鑒於此代碼:

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

    }
}

在 iPhone 8 Plus 上,文本字段向上移動。 我們認為這不應該發生,因為 TextField 不會被鍵盤隱藏,因此它應該保留在同一個地方。

問題 1:這是一個錯誤,應該向 Apple 報告嗎? 我們認為這是一個錯誤/問題。

我們發現使用以下方法:

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

TextField 將移動到鍵盤正上方。 這是預期的行為。 我們還發現使用以下代碼:

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

TextField 不會移動,因為它永遠不會被 TextField 覆蓋。 再一次,這是我們期望的行為。 但是,屏幕中心內和周圍的任何 TextField 似乎鍵盤避免將 TextField 移動到它不應該移動的場景中。

問題 2我們的應用程序在某些屏幕的中心和周圍保留了 TextFields,因此上面發現的問題只會增加糟糕的用戶體驗,因此我們希望“關閉”提供給我們的鍵盤避免功能。 我們希望使用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
        }
                
    }
}

觀察到的結果是修飾符根本不起作用。 TextField 仍然向上移動。 但是,當使用這樣的東西時:

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修飾符是否也有錯誤? 這是應該報告的事情嗎?

屏幕中心及其周圍的 TextField 似乎存在潛在問題?

問題 3有人知道解決這些問題的方法嗎? 因為現在它是 iOS14 上的一個大問題。 鍵盤回避不起作用,任何嘗試關閉它的嘗試也不起作用。

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

更新

我們發現將 TextField 包裝在 Geometry Reader 中,這似乎“關閉”了 TextField 的鍵盤回避。 然而,我們認為這是一個令人愉快的 hack,它以一種方式解決了問題,但同時也暴露了鍵盤回避在幾何閱讀器中不起作用,這可能是其他人的錯誤/問題......

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
        }
                
    }
}

您描述的行為都是預期的。 我們需要明白三件事:

  1. SwiftUI 布局系統
  2. 鍵盤安全區
  3. 忽略安全區域

(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) ignoresSafeArea 修飾符通常應用於具有靈活高度的視圖。 以底部邊緣為例,只有當視圖的原始底部邊緣剛好與底部安全區域的頂部邊緣對齊或被底部安全區域覆蓋時,修改器才會起作用。 因此,如果視圖的底部邊緣遠離底部安全區域的頂部邊緣,則 ignoresSafeArea 將不起作用。

現在我將解釋為什么你所有的例子都有預期的行為。

示例 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里面有一個Spacer,所以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沒有效果。 但是容器並沒有忽略SafeArea,所以當鍵盤顯示時容器的高度仍然降低。

示例 4

struct ContentView: View {

    @State var text: String = ""

    var body: some View {
        VStack {
            Spacer()
            TextField("Testing", text: $text)
        }
        .ignoresSafeArea(.keyboard, edges: .bottom)
    }
}

行為:鍵盤顯示時文本字段不移動,ignoresSafeArea 正在工作。

原因:這次 Spacer 會讓 VStack 擴展它的高度。 請記住,容器不會忽略安全區域,因此如果未應用 ignoresSafeArea 修飾符,當鍵盤顯示時,VStack 的底部邊緣將與底部安全區域的頂部邊緣對齊。 所以這一次如果應用了ignoresSafeArea,它就會起作用並使VStack擴展其高度以忽略鍵盤底部安全區域。

另一個示例可以幫助您了解父視圖如何尊重安全區域而子視圖可以忽略它們。

示例 5:

struct ContentView: View {
    var body: some View {
        ZStack {
            Color.yellow
            Color.green
                .frame(width: 200)
                .ignoresSafeArea()
        }
        .border(Color.blue, width: 10)
    }
}

行為:

截屏

從藍色邊框,我們看到父 ZStack 尊重安全區域,而綠色子視圖忽略安全區域。

關閉鍵盤回避

要關閉 iOS 14 鍵盤回避,您可以將 ignoresSafeArea 應用於擴展其高度的父視圖,例如

struct ContentView: View {

    @State var text: String = ""

    var body: some View {
        ZStack {
            Color.clear
            VStack {
                TextField("Testing", text: $text)
            }
        }
        .ignoresSafeArea(.keyboard)
    }
}

在這個例子中,Color.clear 擴展了它的高度,使 ZStack 擴展了它的高度,因此 ZStack 將忽略鍵盤安全區域。 VStack 位於 ZStack 的中心,因此不受鍵盤的影響。

在這里你可以看到我根據你的 GeometryReader hack 得出的結論: https : //stackoverflow.com/a/63971318/2645599

我的情況是我不想避免任何鍵盤操作,並且我的主視圖控制器中有多個托管控制器。

這是我如何處理EditTextOverlayView類型的:

struct EditTextOverlayViewWrapper: View {

    var observed: ObservedTextEditing

    var body: some View {
        GeometryReader { geometry in
            EditTextOverlayView(observing: observed)
        }.ignoresSafeArea(.keyboard, edges: .bottom)
    }
}

這使所有內容都保持在鍵盤出現時的位置,使我可以進行自定義調整,而不會受到鍵盤回避的干擾。 (觀察到的 var 只是通過包裝器傳遞;否則,視圖功能與包裝的EditTextOverlayView完全相同。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM