🐡

【SwiftUI】iOSアプリでポップオーバーを実装する

2023/12/11に公開

iOS16.4からポップオーバーが実装できるようになっています。

sheetと使い方は似ています。popoverの引数isPresentedに値をバインディングします。sheet同様、特定のitemを使用してポップオーバーを表示することも可能です。

一見これだけで実装できそうですが、ポップオーバーとして表示するViewに対して.presentationCompactAdaptation(PresentationAdaptation.popover)を適用させる必要があります。もし適用を忘れた場合は、sheetと同様にモーダルとして表示されます。

ポップオーバーは表示中、ポップオーバー外をタップすることで閉じることができます。

使い所としては、アプリの初回起動時に便利だと思います。
(使い方をポップオーバーを用いて説明など)


struct ContentView: View {
    @State private var isShowPopover = false
    
    var body: some View {
        ZStack {
            Color(uiColor: .systemGray6).ignoresSafeArea()
            
            Button("Tap me.") {
                isShowPopover = true
            }
            .font(.title)
            .fontWeight(.semibold)
            .padding()
            .popover(isPresented: $isShowPopover) {
                Tapover()
                    .presentationCompactAdaptation(PresentationAdaptation.popover)
            }
        }
    }
}

struct Tapover: View {
    let emojis = ["😎", "😂", "😤", "😭", "🤔", "😱", "😆", "🥺"]
    
    var body: some View {
        Text(emojis.randomElement()!)
            .font(.title)
            .padding()
    }
}

ちなみにポップオーバーの表示位置は勝手に調整してくれます。

以下のコードで確認できます

struct ContentView: View {
    @State private var isShowPopover1 = false
    @State private var isShowPopover2 = false
    @State private var isShowPopover3 = false
    @State private var isShowPopover4 = false
    
    var body: some View {
        ZStack {
            Color(uiColor: .systemGray6).ignoresSafeArea()
            VStack {
                Button("Click") {
                    isShowPopover1 = true
                }
                .padding()
                .popover(isPresented: $isShowPopover1, content: {
                    Text("😎")
                        .padding()
                        .presentationCompactAdaptation(.popover)
                })
                
                Spacer()
                Button("Click") {
                    isShowPopover2 = true
                }
                .padding()
                .popover(isPresented: $isShowPopover2, content: {
                    Text("😎")
                        .padding()
                        .presentationCompactAdaptation(.popover)
                })
                Button("Click") {
                    isShowPopover3 = true
                }
                .padding()
                .popover(isPresented: $isShowPopover3, content: {
                    Text("😎")
                        .padding()
                        .presentationCompactAdaptation(.popover)
                })
                
                Spacer()
                
                Button("Click") {
                    isShowPopover4 = true
                }
                .padding()
                .popover(isPresented: $isShowPopover4, content: {
                    Text("😎")
                        .padding()
                        .presentationCompactAdaptation(.popover)
                })
            }
        }
    }
}

追記

ふと好奇心でポップオーバーの複数表示を試みたところできませんでした。以下のコードの場合、どちらのポップオーバーも表示されません。

struct ContentView: View {
    var body: some View {
        Text("A")
            .padding()
            .popover(isPresented: .constant(true), content: {
                Text("😎")
                    .padding()
                    .presentationCompactAdaptation(.popover)
            })
        
        Text("B")
            .padding()
            .popover(isPresented: .constant(true), content: {
                Text("😎")
                    .padding()
                    .presentationCompactAdaptation(.popover)
            })
    }
}

Discussion