77 votes

La modalité de licenciement de SwiftUI

Puisque SwiftUI est déclaratif, il n'y a pas de dismiss méthode. Comment ajouter un bouton de renvoi/fermeture à l'écran de l'application DetailView ?

struct DetailView: View {
  var body: some View {
  Text("Detail")
  }
}

struct ContentView : View {
  var body: some View {
  PresentationButton(Text("Click to show"), destination: DetailView())
  }
}

1 votes

Aucun des exemples que j'ai vus n'a de méthode pour rejeter une vue présentée, donc je ne pense pas qu'il y en ait encore une.

0 votes

Je suis presque sûr qu'ils vont l'introduire dans la prochaine version bêta. La méthode Pop est également absente.

2 votes

Je pense qu'il est important de se rappeler que SwiftUI est un changement de paradigme. Nous devons penser davantage en termes d'" état " et moins en termes d'écriture d'instructions conditionnelles, etc. Ainsi, comme d'autres l'ont écrit, il s'agit davantage d'écouter l'état via la fonction @Environment ou @State ou d'autres "Property Wrappers". Il s'agit d'un passage au modèle de l'observateur dans un cadre déclaratif, pour ceux qui aiment les phrases compliquées :-)

110voto

MohammadRF Points 1458

Utilisation de l'enveloppe de la propriété @State (recommandé)

struct ContentView: View {
    @State private var showModal = false

    var body: some View {
       Button("Show Modal") {
          self.showModal.toggle()
       }.sheet(isPresented: $showModal) {
            ModalView(showModal: self.$showModal)
        }
    }
}

struct ModalView: View {
    @Binding var showModal: Bool

    var body: some View {
        Text("Modal view")
        Button("Dismiss") {
            self.showModal.toggle()
        }
    }
}

Utilisation de presentationMode

Vous pouvez utiliser presentationMode dans votre vue modale et en appelant self.presentaionMode.wrappedValue.dismiss() pour rejeter le modal :

struct ContentView: View {

  @State private var showModal = false

  // If you are getting the "can only present once" issue, add this here.
  // Fixes the problem, but not sure why; feel free to edit/explain below.
  @SwiftUI.Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>

  var body: some View {
    Button(action: {
        self.showModal = true
    }) {
        Text("Show modal")
    }.sheet(isPresented: self.$showModal) {
        ModalView()
    }
  }
}

struct ModalView: View {

  @Environment(\.presentationMode) private var presentationMode

  var body: some View {
    Group {
      Text("Modal view")
      Button(action: {
         self.presentationMode.wrappedValue.dismiss()
      }) {
        Text("Dismiss")
      }
    }
  }
}

enter image description here

0 votes

Merci pour l'indication sur l'environnement. Comment accéder à isPresented pour l'extérieur comme dans mon exemple ?

0 votes

C'est une nouvelle pour moi. Merci.

0 votes

Bonne trouvaille ! Cependant, pour moi (utilisant Xcode 11 Beta 3), cela ne fonctionne qu'une seule fois lorsque le PresentationLink est utilisé à l'intérieur d'une liste ou d'un navigationBarItems. Je peux présenter et rejeter la vue une fois à partir de chaque bouton.

26voto

thiezn Points 1317

Dans Xcode Beta 5, une autre façon de procéder consiste à utiliser @State dans la vue qui lance la modale, et à ajouter une liaison dans la vue de la modale pour contrôler la visibilité de la modale. Cela ne nécessite pas d'accéder à la variable @Environment presentationMode.

struct MyView : View {
    @State var modalIsPresented = false

    var body: some View {
        Button(action: {self.modalIsPresented = true})  {
            Text("Launch modal view")
        }
        .sheet(isPresented: $modalIsPresented, content: {
            MyModalView(isPresented: self.$modalIsPresented)
        })
    }
}

struct MyModalView : View {
    @Binding var isPresented: Bool

    var body: some View {
        Button(action: {self.isPresented = false})  {
            Text("Close modal view")
        }
    }
}

4 votes

Félicitations pour avoir respecté les principes de SwiftUI avec l'approche déclarative et la source unique de vérité.

2 votes

Cela ne fonctionne que la première fois, si je ferme et réessaie d'ouvrir la fenêtre, cela ne fonctionne plus.

1 votes

Cela semble fonctionner correctement pour moi, peut-être modifiez-vous la valeur isPresented ailleurs ? Par exemple, si vous renvoyez la modale en la tirant vers le bas, swiftUI bascule automatiquement la valeur. Au lieu de régler explicitement la valeur sur true/false, essayez d'utiliser isPresented.toggle().

21voto

Sada Points 1298

Voici une façon d'écarter le point de vue présenté.

struct DetailView: View {
    @Binding
    var dismissFlag: Bool

    var body: some View {
        Group {
            Text("Detail")
            Button(action: {
                self.dismissFlag.toggle()
            }) {
                Text("Dismiss")
            }
        }

    }
}

struct ContentView : View {
    @State var dismissFlag = false

    var body: some View {
        Button(action: {
            self.dismissFlag.toggle()
        })
        { Text("Show") }
            .presentation(!dismissFlag ? nil :
                Modal(DetailView(dismissFlag: $dismissFlag)) {
                print("dismissed")
            })
    }
}

enter image description here

1 votes

Merci, mais si l'utilisateur fait glisser pour rejeter, il faut appuyer deux fois sur la bascule. Il est possible de contourner ce problème en changeant l'état. self.dismissFlag = true; self.dismissFlag = false; . Une solution de contournement, pas une solution. Je cherche également un moyen de désactiver la fonction "glisser-déposer".

0 votes

Je pense que si vous implémentez onDismiss dans le Modal vous pourrez garder dismissFlag en synchronisation. Je n'ai pas essayé pour être sûr.

1 votes

Pour vérifier cela, j'ai testé ce qui se passe avec la fonction self.dismissFlag lors de la suppression de la vue par glisser-déposer. Ajouter onDismiss: { print(self.dismissFlag) } à votre .sheet pour vous tester. Il semble qu'il bascule automatiquement la variable lors du glissement. Notez que la fonction onDismiss ne semble être appelée que lorsque vous faites glisser la vue de la modale. Si vous fermez la modale en basculant la variable self.dismissFlag vous-même le onDismiss n'est pas appelé. (Je suis sur iOS 13 Beta 8)

8voto

Tomm P Points 620

Il semble que pour Xcode 11 Beta 7 (c'est sur la build 11M392r de Xcode) c'est légèrement différent.

@Environment(\.presentationMode) var presentation

Button(action: { self.presentation.wrappedValue.dismiss() }) { Text("Dismiss") }

0 votes

C'est faux. Vous devriez passer une variable d'état qui est également utilisée pour isPresented, plutôt que de jouer avec le presentationMode.

7voto

iOSCS Points 95

Vous pouvez le mettre en œuvre.

struct view: View {
    @Environment(\.isPresented) private var isPresented

    private func dismiss() {
        isPresented?.value = false
    }
}

0 votes

Merci pour l'indication sur l'environnement. Comment accéder à isPresented pour l'extérieur comme dans mon exemple ?

1 votes

C'est faux. Vous devriez passer une variable d'état qui est également utilisée pour isPresented, plutôt que de jouer avec le presentationMode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X