Detect when a SwiftUI sheet is swiped away

Viewed 1475

So I've got a sheet with a cancel button on the left and a done button on the right, like this:

.navigationBarItems(leading: Button(action: {
    // Code that dismisses sheet
}) {
    Text("Cancel")
}, trailing: Button(action: {
    // Code that adds something to something
}) {
    Text("Add").bold()
})

What I want to do is have a block of code execute when my SwiftUI 'sheet' is swiped away (down). This doesn't work with an onDismiss or onDisappear because they both execute on whatever button is pressed AND when it's swiped away.

Is it possible to do this?

1 Answers

onDismiss is enough, you need just to add another variable and check on it.

For example: let's declare an enum

enum SheetAction {
    case cancel
    case nothing
}

Then in your Main View:

@State var sheetAction: SheetAction = SheetAction.nothing

Like that the default action which cause the dismiss will be nothing which means a swipe down, not a button.

And pass it to your SheetView

.sheet(isPresented: self.$sheetActive, onDismiss: {
    if sheetAction == .cancel {
        // dismissed using cancel button
        dismissTxt = "Cancel"
    }else if sheetAction == .nothing {
        // dismissed by swipe down
        dismissTxt = "Swipe down"
    }
}, content: {
    SheetView(isActive: self.$sheetActive, action: self.$sheetAction)
})

When the user click on Cancel button, change its value. And don't miss to change the value to nothing each time the SheetView appears.

The final code:

enum SheetAction {
    case cancel
    case nothing
}

struct CustomView: View {
    
    @State var sheetActive = false
    @State var sheetAction: SheetAction = SheetAction.nothing
    
    @State var dismissTxt = ""
    var body: some View {
        VStack {
            Text(dismissTxt).foregroundColor(.gray)
            Button(action: {
                self.sheetActive = true
            }, label: {
                Text("Button")
            })
        }.sheet(isPresented: self.$sheetActive, onDismiss: {
            if sheetAction == .cancel {
                // dismissed using cancel button
                dismissTxt = "Cancel"
            }else if sheetAction == .nothing {
                // dismissed by swipe down
                dismissTxt = "Swipe down"
            }
        }, content: {
            SheetView(isActive: self.$sheetActive, action: self.$sheetAction)
        })
    }
}

struct SheetView: View {
    @Binding var isActive: Bool
    @Binding var action: SheetAction
    var body: some View {
        NavigationView {
            VStack {
                Text("Sheet content")
            }
            .navigationBarItems(leading: Button(action: {
                // Code that dismisses sheet
                self.action = .cancel
                self.isActive = false
            }) {
                Text("Cancel")
            }, trailing: Button(action: {
                // Code that adds something to something
            }) {
                Text("Add").bold()
            })
        }.onAppear {
            action = .nothing
        }
    }
}

enter image description here

Related