blitz-time アプリ開発ブログ

Androidアプリ開発などのTips集

【SwiftUI開発】ボタンがタッチしても反応しない事象

SwiftUIにてボタンをタッチしても反応しない事象に遭遇しました。

SwiftUIのボタンをタッチしても反応がない

Xcode 14.2
iOS 16.2

操作手順は以下の通り。

  1. TextFieldをタップし、キーボードを表示
  2. sheetで画面Aを表示
  3. 端末の電源ボタンを押して画面ロック
  4. 画面ロック解除
  5. 画面Aを「スワイプダウン」で閉じる
  6. ボタンをタッチしても反応がない。
import SwiftUI

struct SubView: View {
    var body: some View {
        VStack{
           Text("SubView")
        }
    }
}

struct ContentView: View {
    @State var showSheet = false
    @State var message = ""
    
    var body: some View {
        VStack{
            HStack{
                TextField("Message",text: $message)
            }.padding(20)
            
            Button {
                print("Push Me")
            } label: {
                Text("Push Me")
            }
            Spacer()
            Button {
                showSheet = true
            } label: {
                Text("Show")
            }
        }
        .sheet(isPresented: $showSheet, content: {
            SubView()
        })
        .padding(0)
    }
}

考察

色々苦闘の挙句、どうやらタッチできないわけでなく、タッチ領域がなぜか下にずれていることがわかった。
ボタンの下の方をタップすると反応する。意味がわからない。

原因の1つとして「Spacer()」を利用していることらしい。これがないと事象は発生しない。
しかし、レイアウト上、高さが変動する領域が必要。

ひたすら海外の類似事象を探したところ、下記の解決方法を見つけた。

ベストな解決方法

        .sheet(isPresented: $showSheet, content: {
            SubView().presentationDetents([.fraction(0.999)])
        })

iOS16から利用できる「ハーフモーダル」を利用すると事象が改善された。
逆にいうと、ハーフモーダルが追加されたことによる不具合ではないかと思うが。。。

代替解決方法

また、この事象は下記の方法でも解決できることがわかっている。

sheetで表示した画面を「スワイプ」でなく、dismissで終了する。

struct SubView: View {
   @Environment(\.dismiss) var dismiss
    var body: some View {
        VStack{
            Button {
                dismiss()
            } label: {
                Text("Close")
            }
        }
    }
}

sheetの代わりに、fullScreenCoverを利用する

        .fullScreenCover(isPresented: $showingModal) {
            SecondView()
        }

単純にsheetをfullScreenCoverに置き換えるだけでできる。ただし、スワイプで画面を閉じることができない。