web-dev-qa-db-fra.com

SwiftUI: Prise en charge de plusieurs modaux

J'essaie de configurer une vue qui peut afficher plusieurs modaux en fonction du bouton sur lequel vous appuyez.

Lorsque j'ajoute un seul sheet, tout fonctionne:

.sheet(isPresented: $showingModal1) { ... }

Mais lorsque j'ajoute une autre feuille, seule la dernière fonctionne.

.sheet(isPresented: $showingModal1) { ... }
.sheet(isPresented: $showingModal2) { ... }

METTRE À JOUR

J'ai essayé de faire fonctionner cela, mais je ne sais pas comment déclarer le type de modal. Je reçois une erreur de Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements.

struct ContentView: View {
    @State var modal: View?
    var body: some View {
        VStack {
            Button(action: {
                self.modal = ModalContentView1()
            }) {
                Text("Show Modal 1")
            }
            Button(action: {
                self.modal = ModalContentView2()
            }) {
                Text("Show Modal 2")
            }
        }.sheet(item: self.$modal, content: { modal in
            return modal
        })
    }
}

struct ModalContentView1: View {
    var body: some View {
        Text("Modal 1")
    }
}

struct ModalContentView2: View {
    var body: some View {
        Text("Modal 2")
    }
}
24
keegan3d

Peut-être que j'ai raté le point, mais vous pouvez y parvenir soit avec un seul appel à .sheet(), ou plusieurs appels .:

Approche multiple .sheet():

import SwiftUI

struct MultipleSheets: View {
    @State private var sheet1 = false
    @State private var sheet2 = false
    @State private var sheet3 = false

    var body: some View {
        VStack {

            Button(action: {
                self.sheet1 = true
            }, label: { Text("Show Modal #1") })
            .sheet(isPresented: $sheet1, content: { Sheet1() })

            Button(action: {
                self.sheet2 = true
            }, label: { Text("Show Modal #2") })
            .sheet(isPresented: $sheet2, content: { Sheet2() })

            Button(action: {
                self.sheet3 = true
            }, label: { Text("Show Modal #3") })
            .sheet(isPresented: $sheet3, content: { Sheet3() })

        }
    }
}

struct Sheet1: View {
    var body: some View {
        Text("This is Sheet #1")
    }
}

struct Sheet2: View {
    var body: some View {
        Text("This is Sheet #2")
    }
}

struct Sheet3: View {
    var body: some View {
        Text("This is Sheet #3")
    }
}

approche Single .sheet ():

struct MultipleSheets: View {
    @State private var showModal = false
    @State private var modalSelection = 1

    var body: some View {
        VStack {

            Button(action: {
                self.modalSelection = 1
                self.showModal = true
            }, label: { Text("Show Modal #1") })

            Button(action: {
                self.modalSelection = 2
                self.showModal = true
            }, label: { Text("Show Modal #2") })

            Button(action: {
                self.modalSelection = 3
                self.showModal = true
            }, label: { Text("Show Modal #3") })

        }
        .sheet(isPresented: $showModal, content: {
            if self.modalSelection == 1 {
                Sheet1()
            }

            if self.modalSelection == 2 {
                Sheet2()
            }

            if self.modalSelection == 3 {
                Sheet3()
            }
        })

    }
}

struct Sheet1: View {
    var body: some View {
        Text("This is Sheet #1")
    }
}

struct Sheet2: View {
    var body: some View {
        Text("This is Sheet #2")
    }
}

struct Sheet3: View {
    var body: some View {
        Text("This is Sheet #3")
    }
}
25
kontiki

Cela marche:

.background(EmptyView().sheet(isPresented: $showingModal1) { ... }
   .background(EmptyView().sheet(isPresented: $showingModal2) { ... }))

Remarquez comment ils sont imbriqués backgrounds. Pas deux horizons l'un après l'autre.

Merci à DevAndArtist d'avoir trouvé cela.

11
plivesey

Je ne sais pas si cela a toujours été possible, mais dans Xcode 11.3.1 il y a une surcharge de .sheet() pour exactement ce cas d'utilisation ( https://developer.Apple.com/documentation/swiftui/view/3352792-sheet ). Vous pouvez l'appeler avec un élément identifiable au lieu d'un bool:

struct ModalA: View {

    var body: some View {
        Text("Hello, World! (A)")
    }

}

struct ModalB: View {

    var body: some View {
        Text("Hello, World! (B)")
    }

}

struct MyContentView: View {

    enum Sheet: Hashable, Identifiable {

        case a
        case b

        var id: Int {
            return self.hashValue
        }

    }

    @State var activeSheet: Sheet? = nil

    var body: some View {
        VStack(spacing: 42) {
            Button(action: {
                self.activeSheet = .a
            }) {
                Text("Hello, World! (A)")
            }
            Button(action: {
                self.activeSheet = .b
            }) {
                Text("Hello, World! (B)")
            }
        }
            .sheet(item: $activeSheet) { item in
                if item == .a {
                    ModalA()
                } else if item == .b {
                    ModalB()
                }
            }
    }

}
1
cargath

Personnellement, j'imiterais une API NavigationLink. Ensuite, vous pouvez créer une énumération lavable et décider quelle feuille modale vous souhaitez présenter.

extension View {
  func sheet<Content, Tag>(
    tag: Tag,
    selection: Binding<Tag?>,
    content: @escaping () -> Content
  ) -> some View where Content: View, Tag: Hashable {
    let binding = Binding(
      get: {
        selection.wrappedValue == tag
      },
      set: { isPresented in
        if isPresented {
          selection.wrappedValue = tag
        } else {
          selection.wrappedValue = .none
        }
      }
    )
    return background(EmptyView().sheet(isPresented: binding, content: content))
  }
}

enum ActiveSheet: Hashable {
  case first
  case second
}

struct First: View {
  var body: some View {
    Text("frist")
  }
}

struct Second: View {
  var body: some View {
    Text("second")
  }
}

struct TestView: View {
  @State
  private var _activeSheet: ActiveSheet?

  var body: some View {
    print(_activeSheet as Any)
    return VStack
      {
        Button("first") {
          self._activeSheet = .first
        }
        Button("second") {
          self._activeSheet = .second
        }
      }
      .sheet(tag: .first, selection: $_activeSheet) {
        First()
      }
      .sheet(tag: .second, selection: $_activeSheet) {
        Second()
      }
  }
}
0
DevAndArtist