Reputation: 151
Follow-up question to iOS14 introducing errors with @State bindings
I was displaying a modal sheet from several options, depending on which button was pressed. However, now in iOS14 I get a fatal error caused by the selectedSpeaker/selectedMicrophone/selectedAmp being nil when the sheet displays. I am trying to change to .sheet(item:, content:)
but I can't see how to implement the enum and then pass in the appropriate selected object. This is what I was doing previously:
enum ActiveSheet {
case speakerDetails, micDetails, ampDetails, settings
}
struct FavoritesView: View {
@State private var selectedSpeaker: Speaker?
@State private var selectedMicrophone: Microphone?
@State private var selectedAmp: Amplifier?
@State private var showingSheet = false
@State private var activeSheet: ActiveSheet = .settings
var body: some View {
List {
Button(action: {
self.activeSheet = .settings
self.showingSheet = true
}, label: { Text("Settings")})
Button(action: {
self.activeSheet = .micDetails
self.selectedMicrophone = microphones[0]
self.showingSheet = true
}, label: { Text("Mic 1")})
Button(action: {
self.activeSheet = .micDetails
self.selectedMicrophone = microphones[1]
self.showingSheet = true
}, label: { Text("Mic 2")})
Button(action: {
self.activeSheet = .speakerDetails
self.showingSheet = true
self.selectedSpeaker = speakers[0]
}, label: { Text("Speaker 1")})
Button(action: {
self.activeSheet = .speakerDetails
self.showingSheet = true
self.selectedSpeaker = speakers[1]
}, label: { Text("Speaker 2")})
//and so on for activeSheet = .ampDetails in the same way.
}
.sheet(isPresented: self.$showingSheet) {
if self.activeSheet == .speakerDetails {
SpeakerDetailView(speaker: self.selectedSpeaker!)
}
else if self.activeSheet == .micDetails {
MicDetailView(microphone: self.selectedMicrophone!)
}
else if self.activeSheet == .ampDetails {
AmpDetailView(amp: self.selectedAmp!)
} else if self.activeSheet == .settings {
SettingsView(showSheet: self.$showingSheet))
}
}
}
}
}
Upvotes: 2
Views: 640
Reputation: 54486
Here is another approach for your problem which uses sheet(item:content:)
struct ContentView: View {
@State private var selectedSpeaker: Speaker?
@State private var selectedMicrophone: Microphone?
@State private var selectedAmp: Amplifier?
@State private var showSettingsSheet = false
var body: some View {
List {
settingsSection
microphonesSection
// more sections
}
}
var settingsSection: some View {
Button(action: {
self.showSettingsSheet = true
}) {
Text("Settings")
}
.sheet(isPresented: self.$showSettingsSheet) {
SettingsView()
}
}
@ViewBuilder
var microphonesSection: some View {
Button(action: {
self.selectedMicrophone = microphones[0]
}) {
Text("Mic 1")
}
Button(action: {
self.selectedMicrophone = microphones[1]
}) {
Text("Mic 2")
}
.sheet(item: self.$selectedMicrophone) {
MicDetailView(microphone: $0)
}
}
}
This way you also don't need enum ActiveSheet
.
You can always use @Environment(\.presentationMode)
to dismiss a sheet, no need to pass the variable to the sheet (as in SettingsView(showSheet: self.$showingSheet)
):
struct SettingsView: View {
@Environment(\.presentationMode) private var presentationMode
var body: some View {
Text("SettingsView")
.onTapGesture {
presentationMode.wrappedValue.dismiss()
}
}
}
Upvotes: 1