SwiftUI: поддержка нескольких модальных
Я пытаюсь настроить вид, который может отображать несколько модальных режимов в зависимости от того, какая кнопка нажата.
Когда я добавляю только один sheet
, все работает:
.sheet(isPresented: $showingModal1) { ... }
Но когда я добавляю другой лист, работает только последний.
.sheet(isPresented: $showingModal1) { ... }
.sheet(isPresented: $showingModal2) { ... }
ОБНОВИТЬ
Я пытался заставить это работать, но я не уверен, как объявить тип для modal
. Я получаю сообщение об ошибке 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")
}
}
Ответы
Ответ 1
Может быть, я упустил момент, но вы можете достичь этого либо с помощью одного вызова .sheet()
, либо нескольких вызовов.
Многократный .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")
}
}
Единый подход .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")
}
}
Ответ 2
Это работает:
.background(EmptyView().sheet(isPresented: $showingModal1) { ... }
.background(EmptyView().sheet(isPresented: $showingModal2) { ... }))
Обратите внимание, как они вложены backgrounds
. Не два фона один за другим.
Спасибо DevAndArtist за это.
Ответ 3
Я лично подражал бы некоторому API NavigationLink. Затем вы можете создать хешируемое перечисление и решить, какой модальный лист вы хотите представить.
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()
}
}
}
Ответ 4
Два альтернативных метода
- Каждое представление имеет свойство
@State
:
import SwiftUI
struct PresentView: View {
var body: some View {
List(0..<5) { index in
PresentCellView()
}
}
}
struct PresentCellView: View {
@State private var isPresented = false
var body: some View {
Button(action: { self.isPresented.toggle()
}, label: {
Text("Tap to present")
}).sheet(isPresented: $isPresented) {
NavigationView {
PresentingDemoView(showingModal: self.$isPresented)
.navigationBarItems(leading: Button(action: { self.isPresented.toggle()
}, label: {
Text("Cancel")
})
)
}
}
}
}
struct PresentingDemoView: View {
@Binding var showingModal: Bool
var body: some View {
Text("Presenting Demo View")
}
}
struct PresentView_Previews: PreviewProvider {
static var previews: some View {
PresentView()
}
}
- поделиться одним
.sheet
:
struct PresentView: View {
@State private var isPresented = false
@State private var presentingIndex = 0 // or class/structure object
var body: some View {
List(0..<5) { index in //or VStack,HStack...
Button(action: {
self.isPresented.toggle()
self.presentingIndex = index
}, label: {
Text("Tap to present:\(index)")
})
}
.sheet(isPresented: $isPresented) {
NavigationView {
PresentingDemoView(showingModal: self.$isPresented, index: self.$presentingIndex)
.navigationBarItems(leading: Button(action: { self.isPresented.toggle()
}, label: {
Text("Cancel")
})
)
}
}
}
}
struct PresentingDemoView: View {
@Binding var showingModal: Bool
@Binding var index: Int
var body: some View {
Text("Presenting Demo View -- \(index)")
}
}
struct PresentView_Previews: PreviewProvider {
static var previews: some View {
PresentView()
}
}