SwiftUI キーボードを表示時に特定の View を非表示にする

たとえばこんなコードで ScrollView 内に TextField を置いて、さらにスクロール位置によらないで常に画面下部にある View が表示されるような構成を ZStack で表現すると

import SwiftUI

struct ContentView: View {
    @State private var text: String = ""
    let bottomBoxHeight: CGFloat = 150
    
    var body: some View {
        ZStack {
            ScrollView(.vertical, showsIndicators: true) {
                VStack {
                    ForEach(0..<20) { (i) in
                        TextField("Textfield\(i)", text: $text)
                            .padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 33))
                            .overlay(
                                RoundedRectangle(cornerRadius: 30)
                                    .stroke(Color(.systemGray3), lineWidth: 1)
                            )
                        
                        Spacer()
                            .frame(height: 10)
                    }
                    
                    Spacer()
                        .frame(height: bottomBoxHeight)
                }.padding()
            }
            
            VStack {
                Spacer()
                
                Group {
                    Text("Bottom box")
                        .font(.headline)
                        .foregroundColor(.white)
                }
                .frame(minWidth: 0, idealWidth: .infinity, maxWidth: .infinity,
                       minHeight: 0, idealHeight: bottomBoxHeight, maxHeight: bottomBoxHeight,
                       alignment: .center)
                .background(Color(.red))
            }
        }
    }
}

こういうふうに TextField のキーボードを開いた時に、キーボード上に View が重なってしまい、TextField が見えなくなってしまう。(入力できない)

キーボードを表示した時に特定の View を非表示にできれば解決しそう、と考えて調べてみると

KeyboardObserving というライブラリがあり、これを使って対応できた。

https://github.com/nickffox/KeyboardObserving

使い方は、まずアプリのエントリで最初の View を表示する部分のコードで .environmentObject(Keyboard()) を追加する。
(これをしないと、このあと追加するコードでクラッシュする)

import SwiftUI

import KeyboardObserving

@main
struct SwiftUIHideOnKeyboardSampleAppApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(Keyboard())    // これを追加
        }
    }
}

あとは問題が起きている View に以下を追加する。

ScrollView(.vertical, showsIndicators: true) {
    KeyboardObservingView { // KeyboardObservingView にキーボード表示を監視したい View を追加する
        VStack {
            // .... 中略 ....
        }.padding()
    }
}

// .... 中略 ....

VStack {
    // .... 中略 ....
}
.hideOnKeyboard()    // キーボードを表示した時に非表示にしたい View に .hideOnKeyboard() を追加する

これでキーボード表示時に、TextField が隠されることは無くなった。

今回の記事の完全なコードは GitHub にある。

https://github.com/daisuke-t-jp/SwiftUIHideOnKeyboardSampleApp