Reputation: 46479
I am working on a view that will act as a custom button. It consists of 2 elements a ZStack
and Image
that should animate when button is pressed in and released. Both have slightly different animation. To do this I am essentially toggling a state upon which animations are based.
I was able to get where I want with a following onLongPressGesture
property, but it has issues, mainly:
onTapGesture
to this button to perform an action. And doing so inside long pres's perform: {}
requires me to wait for a second or so without releasing a button, which is not ideal. Ideally action should be performed once user releases a finger.I'm not sure long press is the right tool to use here, but I can't seem to find any other way that allows me to explicitly toggle my state with granular control. Ideally I would know exactly when button is pressed and when it is released, with action executing inside .onTapGesture
struct ButtonIcon: View {
// Public Variables
let resource: ImageResource
// Private Variables
@State private var taping = false
// Body
var body: some View {
ZStack {
Image(resource)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.scaleEffect(taping ? 1.1 : 1)
}
.padding(12)
.scaleEffect(taping ? 0.8 : 1)
.onLongPressGesture(
perform: {},
onPressingChanged: { pressing in
withAnimation(.smooth(duration: 0.2)) {
taping.toggle()
}
}
)
}
}
Upvotes: 1
Views: 1971
Reputation: 331
struct CustomButtom: View {
@State private var tapping: Bool = false
var body: some View {
ZStack {
Image(systemName: "heart.fill")
.resizable()
.scaledToFit()
.foregroundStyle(Color.pink)
.frame(width: 100, height: 100)
.scaleEffect(tapping ? 1.1 : 1)
}
.padding(12)
.scaleEffect(tapping ? 0.8 : 1)
.gesture(
DragGesture(minimumDistance: 0)
.onChanged({ value in
withAnimation(.smooth(duration: 0.2)) {
tapping = true
}
})
.onEnded({ value in
withAnimation(.bouncy(duration: 0.5)) {
tapping = false
}
})
)
Text(tapping ? "Pressing" : "Not pressing")
}
}
Output: https://i.sstatic.net/FJ5zO.gif
Upvotes: 3