複数のシート(isPresented :)がSwiftUIで機能しない


21

このContentViewには2つの異なるモーダルビューがあり、sheet(isPresented:)両方に使用していますが、最後のビューのみが表示されるようです。この問題を解決するにはどうすればよいですか?または、SwiftUIのビューで複数のシートを使用することはできませんか?

struct ContentView: View {

    @State private var firstIsPresented = false
    @State private var secondIsPresented = false

    var body: some View {

        NavigationView {
            VStack(spacing: 20) {
                Button("First modal view") {
                    self.firstIsPresented.toggle()
                }
                Button ("Second modal view") {
                    self.secondIsPresented.toggle()
                }
            }
            .navigationBarTitle(Text("Multiple modal view problem"), displayMode: .inline)
            .sheet(isPresented: $firstIsPresented) {
                    Text("First modal view")
            }
            .sheet(isPresented: $secondIsPresented) {
                    Text("Only the second modal view works!")
            }
        }
    }
}

上記のコードは警告なしにコンパイルされます(Xcode 11.2.1)。


シートは1つだけです。このソリューションのショーは、どのように自分の状況に似ている別のアラートを持っているし、おそらく簡単に再利用することができstackoverflow.com/questions/58737767/...
アンドリュー・

回答:


27

以下のコードを試してください

enum ActiveSheet {
   case first, second
}

struct ContentView: View {

    @State private var showSheet = false
    @State private var activeSheet: ActiveSheet = .first

    var body: some View {

        NavigationView {
            VStack(spacing: 20) {
                Button("First modal view") {
                    self.showSheet = true
                    self.activeSheet = .first
                }
                Button ("Second modal view") {
                    self.showSheet = true
                    self.activeSheet = .second
                }
            }
            .navigationBarTitle(Text("Multiple modal view problem"), displayMode: .inline)
            .sheet(isPresented: $showSheet) {
                if self.activeSheet == .first {
                    Text("First modal view")
                }
                else {
                    Text("Only the second modal view works!")
                }
            }
        }
    }
}

1
このソリューションは理にかなっており、拡張できます。
チューリングテスト済み

if ... elseの代わりにswitchステートメントを使用してこのコードを試行し、if ... elseが制御フローではないために困惑していたエラー「制御フローステートメントを含む関数フロービルダー 'ViewBuilder'では使用できません」を取得しましたか?
アーロンSurrain

ありがとう!このソリューションは機能します
アデルマー

SheetViewのタイプは同じです:テキスト、タイプはどうですか?私が見る限り、それは機能していません。
QuangHà

@QuangHàそのためには別の方法で行う必要があります。または、2つ以上のSheetViewを異なるアプローチとして使用することもできます
Rohit Makwana

11

次の方法で解決できる場合があります(Xcode 11.2でテスト済み)

var body: some View {

    NavigationView {
        VStack(spacing: 20) {
            Button("First modal view") {
                self.firstIsPresented.toggle()
            }
            .sheet(isPresented: $firstIsPresented) {
                    Text("First modal view")
            }
            Button ("Second modal view") {
                self.secondIsPresented.toggle()
            }
            .sheet(isPresented: $secondIsPresented) {
                    Text("Only the second modal view works!")
            }
        }
        .navigationBarTitle(Text("Multiple modal view problem"), displayMode: .inline)
    }
}

アラートは1つですが、偽であるが真の場合は(体外で)複数のブール値があるため、アラートにどのブール値が真であるかを知らせて、特定のアラートを表示します
Dewan

6

ビューの背景に配置されたEmptyViewにシートを追加することもできます。これは複数回実行できます。

  .background(EmptyView()
        .sheet(isPresented: isPresented, content: content))

3

これは、ボタンと.sheet呼び出しをグループ化するだけで実現できます。あなたが1つの先行と1つの後続がある場合、それはとても簡単です。ただし、先頭または末尾に複数のnavigationbaritemsがある場合は、それらをHStackでラップし、各ボタンをシート呼び出しでVStackでラップする必要があります。

次に、2つの末尾ボタンの例を示します。

            trailing:
            HStack {
                VStack {
                    Button(
                        action: {
                            self.showOne.toggle()
                    }
                    ) {
                        Image(systemName: "camera")
                    }
                    .sheet(isPresented: self.$showOne) {
                        OneView().environment(\.managedObjectContext, self.managedObjectContext)
                    }
                }//showOne vstack

                VStack {
                    Button(
                        action: {
                            self.showTwo.toggle()
                    }
                    ) {
                        Image(systemName: "film")
                    }
                    .sheet(isPresented: self.$showTwo) {
                        TwoView().environment(\.managedObjectContext, self.managedObjectContext)
                    }
                }//show two vstack
            }//nav bar button hstack

1

Rohit Makwanaの回答に加えて、コンパイラーが巨大な型チェックを行うのに苦労したため、シートの内容を関数に抽出する方法を見つけましたView

extension YourView {
    enum Sheet {
        case a, b
    }

    @ViewBuilder func sheetContent() -> some View {
        if activeSheet == .a {
            A()
        } else if activeSheet == .b {
            B()
        }
    }
}

次のように使用できます。

.sheet(isPresented: $isSheetPresented, content: sheetContent)

これにより、コードがよりクリーンになり、コンパイラのストレスも軽減されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.