iOS14のSwiftUIのキーボード回避の問題とIgnoresSafeArea修飾子の問題 質問する

iOS14のSwiftUIのキーボード回避の問題とIgnoresSafeArea修飾子の問題 質問する

iOS13 では、TextField にキーボード回避処理が一切実装されていませんでした。そのため、うまく機能する独自のキーボード回避メカニズムを作成しました。iOS14 にアップグレードした結果、TextField にキーボード回避が組み込まれました。ただし、キーボード回避は期待どおりに機能していないようです。

第1号私たちが経験した最初の問題は、画面の中央付近の TextFields でキーボード回避が期待どおりに機能しないことでした。次のコードを想定します。

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

    }
}

iPhone 8 および iPhone 8 Plus では、テキストフィールドが上に移動します。私たちの意見では、テキストフィールドはキーボードによって隠されることはなく、同じ場所に残るはずなので、これは起きるべきではないと思います。

質問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番目の質問につながります。

質問2修飾子にもバグがありますかignoresSafeArea? これは報告すべきものですか?

画面の中央付近の TextFields に根本的な問題があるように思えます。

質問3これらの問題を回避する方法をご存知の方はいらっしゃいますか? 現在、iOS14 では大きな問題になっています。キーボード回避は機能せず、オフにしようとしても機能しません。

Xcode 12.0 (12A7209) を使用しています

アップデート

TextField を Geometry Reader でラップすると、TextField のキーボード回避が「オフ」になるようです。ただし、これはある意味では問題を解決する素晴らしいハックであると考えていますが、同時にキーボード回避が Geometry Reader では機能しないことが明らかになり、他の人にとってバグや問題になる可能性があります...

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

あなたが説明した動作はすべて想定されたものです。次の 3 つのことを理解する必要があります。

  1. SwiftUIレイアウトシステム
  2. キーボード安全領域
  3. 安全領域を無視

(1) SwiftUIレイアウトシステムで最も重要な概念は、ビューが固定サイズまたは可変サイズを持つことができるということです。たとえば、1行のテキストは固定サイズです。したがって、テキストのみを含むVStackも固定サイズです。これを試してみてください。

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello")
            Text("World")
        }
        .border(Color.green)
    }
}

緑の枠線がテキストの周囲のみを囲んでいることがわかります。

一方、Spacers、Colors、GeometryReaders などはサイズが柔軟であるため、利用可能なスペースをすべて占有するように拡張する傾向があります。

(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 修飾子は効果がありません。

理由: ignoresSafeArea は VStack に適用されますが、VStack の高さは固定されており、その下端は下部の安全領域から遠いため、ignoresSafeArea は効果がありません。ただし、コンテナーは ignoresSafeArea を適用しないため、キーボードが表示されるとコンテナーの高さは依然として減少します。

例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 を無視しないことに注意してください。そのため、 ignoresSafeArea 修飾子が適用されていない場合、キーボードが表示されると、VStack の下端が下部の安全領域の上端に揃います。そのため、今回は ignoresSafeArea が適用されると、それが機能し、VStack の高さが拡張されて、キーボードの下部の安全領域が無視されます。

もう 1 つの例は、親ビューが安全領域を尊重し、サブビューが安全領域を無視する方法を理解するのに役立ちます。

例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 の中央に配置されているため、キーボードの影響を受けません。

おすすめ記事