La feuille multiple (isPresented :) ne fonctionne pas dans SwiftUI

22

J'ai cette ContentView avec deux vues modales différentes, donc j'utilise les sheet(isPresented:)deux, mais il semble que seule la dernière soit présentée. Comment pourrais-je résoudre ce problème? Ou n'est-il pas possible d'utiliser plusieurs feuilles sur une vue dans 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!")
            }
        }
    }
}

Le code ci-dessus se compile sans avertissements (Xcode 11.2.1).

testée
la source
Vous ne pouvez avoir qu'une seule feuille. Cette solution montre comment avoir différentes alertes qui sont similaires à votre situation et pourraient probablement être facilement réutilisées stackoverflow.com/questions/58737767/…
Andrew

Réponses:

27

Veuillez essayer ci-dessous le code

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
la source
1
Cette solution est logique et peut évoluer, merci!
testée
J'ai essayé ce code avec l'instruction switch au lieu de if ... else et j'ai obtenu l'erreur "La fermeture contenant l'instruction de flux de contrôle ne peut pas être utilisée avec le générateur de fonctions 'ViewBuilder'", ce qui était déroutant parce que si ... sinon c'est le flux de contrôle?
Aaron Surrain
Merci! Cette solution fonctionne
Adelmaer
Vos SheetViews ont le même type: Texte, que diriez-vous d'un type différent? Pour autant que je vois, cela ne fonctionne pas.
Quang Hà
@ QuangHà pour cela, vous devez le faire d'une autre manière. ou vous pouvez prendre deux ou plusieurs SheetViews comme approche différente que vous avez
Rohit Makwana
12

Votre cas peut être résolu par ce qui suit (testé avec 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
la source
J'ai une alerte mais plusieurs booléens qui sont faux mais une fois vrais (à l'extérieur du corps), alors je veux que mon alerte sache quel booléen est vrai et affiche une certaine alerte
Dewan
6

Peut également ajouter la feuille à un EmptyView placé en arrière-plan de la vue. Cela peut être fait plusieurs fois:

  .background(EmptyView()
        .sheet(isPresented: isPresented, content: content))
Tylerc230
la source
3

Vous pouvez accomplir cela simplement en regroupant le bouton et les appels .sheet ensemble. Si vous avez un premier et un arrière, c'est aussi simple que cela. Cependant, si vous avez plusieurs éléments de barre de navigation dans le début ou la fin, vous devez les envelopper dans un HStack et également envelopper chaque bouton avec son appel de feuille dans un VStack.

Voici un exemple de deux boutons de fin:

            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
user2698617
la source
1

En plus de la réponse de Rohit Makwana , j'ai trouvé un moyen d'extraire le contenu de la feuille vers une fonction parce que le compilateur avait du mal à vérifier le type de mon gigantesque View.

extension YourView {
    enum Sheet {
        case a, b
    }

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

Vous pouvez l'utiliser de cette façon:

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

Il rend le code plus propre et soulage également le stress de votre compilateur.

cayZ
la source