Context
I have a Menu
(including multiple Buttons
) inside a SwiftUI
Toolbar
and a .sheet()
Modifier
inside the Toolbar
, too.
The problem is, that pressing the Button
with the show.toggle()
action does not present the Sheet
as expected.
Please Note: My actual app architecture is more complex than this
MRE
, so moving the.sheet()
outside of theToolbar
is pretty difficult.
Code
struct MainView: View {
var showOption: Option?
var body: some View {
NavigationStack {
Text("Hello World")
.toolbar {
ToolbarItem {
Menu {
... Button(action: { option = .option1 } { ... } ...
}
.sheet(item: $showOption) { option in
switch option {
case .option1: Text("Hello World 1")
...
}
}
}
}
}
}
}
Questions
- Is this caused by the
.sheet()
being inside theToolbar
or is there anything else I missed? - How can I solve this (ideally without moving the
.sheet()
outside of theToolbar
)?
CodePudding user response:
if you move it outside of Menu
(still in Toolbar) it works fine:
struct ContentView: View {
@State private var show: Bool = false
var body: some View {
NavigationStack {
Text("Hello World")
.toolbar {
ToolbarItem {
Menu("Test") {
Button("Show") {
show.toggle()
}
}
.sheet(isPresented: $show) {
Text("Hello World 2")
}
}
}
}
}
}
CodePudding user response:
In SwiftUI whenever we apply a modifier to view it actually create a new view with that change applied instead of modifying the existing view in the place. This behavior makes sense: our views only hold the exact properties we give them. Have a look at the sample code below.
struct ContentView: View {
@State private var show: Bool = false
var body: some View {
NavigationStack {
Text("Hello World")
.toolbar {
ToolbarItem {
Menu("Test") {
Button("Show") {
print(type(of: self.body))
show.toggle()
}
}
.sheet(isPresented: $show) {
Text("Hello World 2")
}
}
}
}
}
}
Swift’s type(of:)
method prints the exact type of a particular view/value, if we add the .sheet
modifier under the Menu, print(of:)
shows the following output
ModifiedContent<Text, ToolbarModifier<(), TupleToolbarContent<ToolbarItem<(), ModifiedContent<Menu<Text, Button>, SheetPresentationModifier>>>>>
Nests the elements in the following way:
Text -> ToolbarModifier -> TupleToolbarContent -> ToolbarItem -> ModifiedContent -> Menu -> Text -> Button -> SheetPresentationModifier
if we add the .sheet
modifier under the button print(of:)
shows the following output
ModifiedContent<Text, ToolbarModifier<(), TupleToolbarContent<ToolbarItem<(), Menu<Text, ModifiedContent<Button, SheetPresentationModifier>>>>>
Nest the elements in the following way: Text -> ToolbarModifier -> TupleToolbarContent -> ToolbarItem -> Menu -> Text -> ModifiedContent -> Button -> SheetPresentationModifier
So, as we discussed earlier that the order of modifier effect on the functionality of SwiftUI. If we add .sheet
to the Menu element then it would have additional functionality or appearance that is specific to the ModifiedContent and shows the sheet. While for the case of button ModifiedContent does not work.