Wiele arkuszy (isPresented :) nie działa w SwiftUI

21

Mam ten ContentView z dwoma różnymi widokami modalnymi, więc używam sheet(isPresented:)dla obu, ale jak się wydaje, tylko ostatni jest prezentowany. Jak mogę rozwiązać ten problem? A może nie można używać wielu arkuszy w widoku w 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!")
            }
        }
    }
}

Powyższy kod kompiluje się bez ostrzeżeń (Xcode 11.2.1).

turingtested
źródło
Możesz mieć tylko jeden arkusz. To rozwiązanie pokazuje, jak mieć różne alerty, które są podobne do twojej sytuacji i prawdopodobnie można je łatwo zmienić przeznaczenie stackoverflow.com/questions/58737767/...
Andrew,

Odpowiedzi:

25

Spróbuj poniżej kodu

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!")
                }
            }
        }
    }
}
Rohit Makwana
źródło
1
To rozwiązanie ma sens i można je skalować, dzięki!
przetestowane w Turing
Wypróbowałem ten kod z instrukcją switch zamiast if ... else i dostałem błąd: „Zamknięcia zawierającego instrukcję przepływu sterowania nie można używać z konstruktorem funkcji„ ViewBuilder ””, co było zaskakujące, ponieważ nie jest, jeśli ... inaczej jest przepływ sterowania?
Aaron Surrain
Dzięki! To rozwiązanie działa
Adelmaer
Twoje widoki arkusza mają ten sam typ: tekst, co powiesz na inny typ? O ile mi wiadomo, to nie działa.
Quang Hà
@ QuangHà, ponieważ musisz to zrobić w inny sposób. lub możesz wziąć dwa lub więcej SheetViews jako inne podejście
Rohit Makwana
11

Twoja sprawa może zostać rozwiązana w następujący sposób (testowane z 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)
    }
}
Asperi
źródło
Mam jeden alert, ale wielokrotny Bool, który jest fałszywy, ale raz jest prawdziwy (poza ciałem), więc chcę, aby mój alert wiedział, który Bool jest prawdziwy i pokazał określony alert
Dewan
6

Można także dodać arkusz do EmptyView umieszczonego w tle widoku. Można to zrobić wiele razy:

  .background(EmptyView()
        .sheet(isPresented: isPresented, content: content))
Tylerc230
źródło
3

Możesz to zrobić po prostu grupując przycisk i wywołania .sheet razem. Jeśli masz jedną wiodącą i jedną końcową, jest to takie proste. Jeśli jednak masz wiele pasków nawigacyjnych na początku lub na końcu, musisz owinąć je w HStack, a także owinąć każdy przycisk wywołaniem arkusza w VStack.

Oto przykład dwóch końcowych przycisków:

            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
użytkownik2698617
źródło
1

Oprócz odpowiedzi Rohita Makwany znalazłem sposób na wyodrębnienie zawartości arkusza do funkcji, ponieważ kompilator z trudem sprawdzał mój gigantyczny typ View.

extension YourView {
    enum Sheet {
        case a, b
    }

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

Możesz użyć tego w ten sposób:

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

Sprawia, że ​​kod jest czystszy, a także odciąża kompilator.

cayZ
źródło