Reputation: 677
I am trying to present a modal sheet upon selecting the menu item in the navigation bar. But, the sheet is not displayed. Upon debugging I noticed that the state variable showSheet
is not getting updated and I am sort of lost as to why it is not updating.
Any help is very much appreciated. Thank you!
There is another post (@State not updating in SwiftUI 2) that has a similar issue. Is this a bug in SwiftUI?
Below is a full sample
I have a fileprivate enum
that defines two cases for the views - add
and edit
fileprivate enum SheetView {
case add, edit
}
Below is the ContentView. The ContentView declares two @State
variables that are set based on the menu item selected
The menu items (var actionItems
) are on the NavigationView
and has menu with 2 buttons - Add and Edit. Each button has an action set to toggle the showSheetView
and the showSheet
variables. The content is presented based on which item is selected. Content is built using @ViewBuilder
struct ContentView: View {
@State private var showSheetView = false
@State private var showSheet: SheetView? = nil
var body: some View {
GeometryReader { g in
NavigationView {
Text("Main Page")
.padding()
.navigationBarTitle("Main Page")
.navigationBarItems(trailing: actionItems)
}
}.sheet(isPresented: $showSheetView) {
content
}
}
var actionItems: some View {
Menu {
Button(action: {
showSheet = .add
showSheetView.toggle()
}) {
Label("Add Asset", systemImage: "plus")
}
Button(action: {
showSheet = .edit
showSheetView.toggle()
}) {
Label("Edit Asset", systemImage: "minus")
}
} label: {
Image(systemName: "dot.circle.and.cursorarrow").resizable()
}
}
@ViewBuilder
var content: some View {
if let currentView = showSheet {
switch currentView {
case .add:
AddAsset(showSheetView: $showSheetView)
case .edit:
EditAsset(showSheetView: $showSheetView)
}
}
}
}
Below are the two Views - AddAsset
and EditAsset
struct AddAsset: View {
@Binding var showSheetView: Bool
var body: some View {
NavigationView {
Text("Add Asset")
.navigationBarTitle(Text("Add"), displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
print("Dismissing sheet view...")
self.showSheetView = false
}) {
Text("Done").bold()
})
}
}
}
struct EditAsset: View {
@Binding var showSheetView: Bool
var body: some View {
NavigationView {
Text("Edit Asset")
.navigationBarTitle(Text("Edit"), displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
print("Dismissing sheet view...")
self.showSheetView = false
}) {
Text("Done").bold()
})
}
}
}
Upvotes: 1
Views: 1674
Reputation: 257711
The solution is to use sheet(item:
variant.
Here is fixed code (there are many changes so all components included). Tested with Xcode 12.1 / iOS 14.1
enum SheetView: Identifiable {
var id: Self { self }
case add, edit
}
struct ContentView: View {
@State private var showSheet: SheetView? = nil
var body: some View {
GeometryReader { g in
NavigationView {
Text("Main Page")
.padding()
.navigationBarTitle("Main Page")
.navigationBarItems(trailing: actionItems)
}
}.sheet(item: $showSheet) { mode in
content(for: mode)
}
}
var actionItems: some View {
Menu {
Button(action: {
showSheet = .add
}) {
Label("Add Asset", systemImage: "plus")
}
Button(action: {
showSheet = .edit
}) {
Label("Edit Asset", systemImage: "minus")
}
} label: {
Image(systemName: "dot.circle.and.cursorarrow").resizable()
}
}
@ViewBuilder
func content(for mode: SheetView) -> some View {
switch mode {
case .add:
AddAsset(showSheet: $showSheet)
case .edit:
EditAsset(showSheet: $showSheet)
}
}
}
struct AddAsset: View {
@Binding var showSheet: SheetView?
var body: some View {
NavigationView {
Text("Add Asset")
.navigationBarTitle(Text("Add"), displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
print("Dismissing sheet view...")
self.showSheet = nil
}) {
Text("Done").bold()
})
}
}
}
struct EditAsset: View {
@Binding var showSheet: SheetView?
var body: some View {
NavigationView {
Text("Edit Asset")
.navigationBarTitle(Text("Edit"), displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
print("Dismissing sheet view...")
self.showSheet = nil
}) {
Text("Done").bold()
})
}
}
}
Upvotes: 3