Skip to content

Instantly share code, notes, and snippets.

@gabrieltheodoropoulos
Created November 1, 2020 17:56
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save gabrieltheodoropoulos/59dc104163b5718018c6c55309b110fb to your computer and use it in GitHub Desktop.
Save gabrieltheodoropoulos/59dc104163b5718018c6c55309b110fb to your computer and use it in GitHub Desktop.
PressActions modifier - Handle press and release events in SwiftUI
struct PressActions: ViewModifier {
var onPress: () -> Void
var onRelease: () -> Void
func body(content: Content) -> some View {
content
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged({ _ in
onPress()
})
.onEnded({ _ in
onRelease()
})
)
}
}
extension View {
func pressAction(onPress: @escaping (() -> Void), onRelease: @escaping (() -> Void)) -> some View {
modifier(PressActions(onPress: {
onPress()
}, onRelease: {
onRelease()
}))
}
}
@olilarkin
Copy link

olilarkin commented Jun 22, 2021

Thankyou for this. I would like to apply a similar thing to a slider, so that I can trigger a function when the slider is initially touched and when it is released. I tried applying your pressAction to a Slider but it prevents the Slider from moving. Do you know a way around that?

    @State private var isPressed = false
    @State private var gain = 0.0
    var body: some View {
        Slider(value: $gain, in: 0...100)
            .pressAction {
                isPressed = true
            } onRelease: {
                isPressed = false
            }
    }
}

@gabrieltheodoropoulos
Copy link
Author

Hi @olilarkin and thanks for your comment.

The PressActions view modifier contains a drag gesture, and that's what actually disables the default slider behavior. I tried to do what you're asking using tap gestures, but that fails too. The same with long press gesture. So I'm not sure if there's an obvious workaround on that purely in SwiftUI. To suggest an idea, you could create a UISlider subclass in UIKit, and override the touchDown and touchUp events. Then bring the slider to SwiftUI with a custom UIViewRepresentable type. This will probably work.

@AdamWhitcroft
Copy link

Hey, thanks for sharing this, I just came across it. While implementing this in an app I’m working on, I discovered something interesting. If you put add a haptic event to both onPress and onRelease (attempting to simulate a mechanical keyboard) the onPress haptic will fire repeatedly if you keep your finger pressed and move it slightly.

Are there any amendments you’d make to your code to somehow account for that?

@gabrieltheodoropoulos
Copy link
Author

Hi @AdamWhitcroft, thanks for your comment. That's an interesting point, I'll check it out at first chance and will get back hopefully with a solution.

@jesseauciello
Copy link

Thanks for this, @gabrieltheodoropoulos. Wondering if you or @AdamWhitcroft ever came up with a solution to his question regarding haptics?

@gabrieltheodoropoulos
Copy link
Author

Hi @jesseauciello. As it seems other tasks took priority and I totally neglected this. Sorry for that, I'll try to work on it the soonest.

@MartinAtElitappar
Copy link

Hi, thanks for the article "Handle Press And Release Events in SwiftUI". I will try to use ButtonStyle or PrimitiveButtonStyle instead. The configuration.isPressed can be used for checking if the button is pressed or released. /Martin

@NyiYe
Copy link

NyiYe commented Feb 23, 2023

how to implement both on tap gesture and pressAction .

@MartinAtElitappar
Copy link

Hi @NyiYe , Are you talking about buttons? Can it work for you to make a custom ButtonStyle and use isPressed? You have the action in the button for the tap gesture. I attach an article "Creating Custom Button Styles In SwiftUI" from Gabriel. (You can maybe explain you needs more?) /Martin

@loryhuz
Copy link

loryhuz commented Oct 8, 2023

Unfortunately this is cancelling the scroll in a scrollview if you move your finger on the modified view

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment