The primary issue is that you're using a shared
state object which is set to true
and never set to false
based on the code you've provided. That means when you first present the sheet, it acts in a way that you're expecting, however the second time you present the sheet, it's only presented briefly then dismissed because you've effectively toggled the boolean to false
on that second button. It looks like this, by execution order; Initialized false
-> Button Tap -> Set true
-> Sheet Presented -> Sheet Dismissed -> Second Button Tap -> Set false
-> Weird behavior.
I also noticed you're using $obsPresentation.triggerSheet
instead of obsPresentation.$triggerSheet
which could also cause the problem, but I recommend below, a better solution regardless. I don't have my IDE right now, so I can't confirm that gut instinct.
So, if you've read this far, then surely, you're wondering, why is the sheet even presenting at all, given that it's set to false
. That's because sheets have a unique behavior where they ignore certain thread actions while they're mid-animation. Your implementation is triggering the sheet to appear, because the @State
is being updated, and in the context of the ViewBuilder
it doesn't care if its true
or false
, simply that it's updated, and it should re-draw. However, while it's in the middle of that re-draw, it's published value flips to false, thus causing the sheet to disappear. Similar weird behavior can happen by dismissing a parent of the sheet, from the parent, while a sheet is presented as proof of this. So how do you fix it?
The best way to fix a sheet, in particular one that you're using for different things, is to use an Enum
in place of a boolean value. For example:
enum PresentedSheet {
case sheetOne, sheetTwo, sheetThree
}
If you were to use an value that is optional, then you can have the sheet be presented, whenever the value is NOT nil. For example:
@State presentedSheet: PresentedSheet? = nil
var body: some View {
Text("Example")
.sheet(item: $presentedSheet) {
switch presentedSheet { //Show the view you want }
}
}
In your case, you'd add the presentedSheet
in place of your boolean, on your observable object. If you want additional controls, there is a callback function that can be called onDismiss
if you need to know or update something when that sheet is dismissed.
As a final note, when working with sheets, if you're sharing a sheet among different views, be sure to have that sheet presented from the parent most view, or if a particular child view is destroyed it will also automatically dismiss your currently presented sheet. Also, don't overuse this as it can quickly clutter your code or complicate things.