見出し画像

[SwiftUI] TextFieldの下にImageを描画するとTextFieldにフォーカスが当たらなくなった件

SwiftUIをつかってiOSアプリの開発をしてるときに予期しないところでハマってしまったので備忘録

事象

タイトルの通り
TextFieldの下にImageを記述すると、TextFieldにフォーカスが当たらなくなる場合があった

試した結果、下記2つの条件が揃ったときにTextFieldにフォーカスが当たらなくなった

  • コード上でTextFieldの下にImageを記述する

    • つまり、TextFieldよりも前面にImageを配置する

  • Imageでは縦長の画像を描画する

サンプルコードは下記の通り

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

    private static let thumbnailRatio: CGFloat = 16 / 9
    private static let roundRect = RoundedRectangle(cornerRadius: 8)

    var body: some View {
        GeometryReader { proxy in
            VStack(spacing: 8) {
                Spacer()

                TextField("", text: $text)
                    .padding(.horizontal, 16)
                    .frame(height: 44)
                    .clipShape(ContentView.roundRect)
                    .overlay(ContentView.roundRect.strokeBorder(Color(.black), lineWidth: 1))

                Image("vertical")
                    .resizable()
                    .scaledToFill()
                    .frame(
                        width: proxy.size.width,
                        height: proxy.size.width / ContentView.thumbnailRatio)
                    .clipped()

                Spacer()
            }
        }
        .padding(.horizontal, 16)
    }
}

検証に使った画像は下記の2つ(括弧内はAsset名)

試したこと1

下記の記事を参考にImageに contentShape(Rectangle()) をつけてみた

結果

だめだった
ただ、TextFieldの代わりにButtonを同じ位置に配置してみるとButtonのタップイベントは発火することが確認できた。
TextFieldも onTapGesture のイベントは発火することが確認できたが、入力待ちの状態にはならなかった

試したこと2

サンプルコードのようにTextField→Imageの順に記述をすると、TextFieldの前面にImageが描画されることになる
TextFieldに zIndex(1) をしていして、強制的にTextFieldの方を前面に描画させてみた

結果

こちらは成功

考察

横長の画像を表示したとき、指定したframe内にImageが描画されていることがわかる(画像の青くなっているレイヤー)
→ resizable, scaledToFillを指定しており、かつ横長の画像なので縦幅に合わせて左右にはみ出ているため、縦方向へ干渉しない

縦長の画像を表示したとき、指定したframeに対して縦方向に長くImageが描画されていることがわかる(画像の青くなっているレイヤー)
→ resizable, scaledToFillを指定しているのは同じだが、画像が縦長のため、横幅に合わせて上下にはみ出しているため、上に配置しているTextFieldに干渉していそう

なんとかframeの枠外にはみ出ている部分をカットしようと調べてみたが、方法が見つからなかったため、zIndexを指定して、Imageよりも前面にTextFieldを描画させることで解消した

まとめ

TextFieldの下にImageで縦長の画像を描画させるとTextFieldにフォーカスが当たらなくなったので、TextFieldを前面に描画させることで解決した

とりあえず困っていたことは一旦解消したのだが、
「試したこと1」で contentShape(Rectangle()) を指定したときにTextFieldのフォーカスは当たらなかったが、 onTapGesture は反応したのが気になる
onTapGestureは反応するのにフォーカスは当たらないのはなぜ、、、、、

この記事が気に入ったらサポートをしてみませんか?