I have a button in SwiftUI and I would like to be able to have a different action for \"tap button\" (normal click/tap) and \"long press\".
Is that possible in Swift
Try this :)
Handles isInactive, isPressing, isLongPress and Tap(Click)
based on this
I tried to make this as a viewmodifier without success. I would like to see an example with @GestureState variable wrapper used in same manner as @State/@Published are bound to @Binding in view components.
Tested: Xcode 12.0 beta, macOS Big Sur 11.0 beta
import SwiftUI
enum PressState {
case inactive
case pressing
case longPress
var isPressing: Bool {
switch self {
case .inactive:
return false
case .pressing, .longPress:
return true
}
}
var isLongPress: Bool {
switch self {
case .inactive, .pressing:
return false
case .longPress:
return true
}
}
var isInactive : Bool {
switch self {
case .inactive:
return true
case .pressing, .longPress:
return false
}
}
}
struct ContentView: View {
@GestureState private var pressState: PressState = PressState.inactive
@State var showClick: Bool = false
var press: some Gesture {
LongPressGesture(minimumDuration: 0.8, maximumDistance: 50.0)
.sequenced(before: LongPressGesture(minimumDuration: .infinity, maximumDistance: 50.0))
.updating($pressState) { value, state, transaction in
switch value {
case .first(true): // first gesture starts
state = PressState.pressing
case .second(true, nil): // first ends, second starts
state = PressState.longPress
default: break
}
}
}
var body: some View {
ZStack{
Group {
Text("Click")
.offset(x: 0, y: pressState.isPressing ? (pressState.isLongPress ? -120 : -100) : -40)
.animation(Animation.linear(duration: 0.5))
.opacity(showClick ? 1 : 0 )
.animation(Animation.linear(duration: 0.3))
Text("Pressing")
.opacity(pressState.isPressing ? 1 : 0 )
.offset(x: 0, y: pressState.isPressing ? (pressState.isLongPress ? -100 : -80) : -20)
.animation(Animation.linear(duration: 0.5))
Text("Long press")
.opacity(pressState.isLongPress ? 1 : 0 )
.offset(x: 0, y: pressState.isLongPress ? -80 : 0)
.animation(Animation.linear(duration: 0.5))
}
Group{
Image(systemName: pressState.isLongPress ? "face.smiling.fill" : (pressState.isPressing ? "circle.fill" : "circle"))
.offset(x: 0, y: -100)
.font(.system(size: 60))
.opacity(pressState.isLongPress ? 1 : (pressState.isPressing ? 0.6 : 0.2))
.foregroundColor(pressState.isLongPress ? .orange : (pressState.isPressing ? .yellow : .white))
.rotationEffect(.degrees(pressState.isLongPress ? 360 : 0), anchor: .center)
.animation(Animation.linear(duration: 1))
Button(action: {
showClick = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
self.showClick = false
})
}, label: {
ZStack {
Circle()
.fill(self.pressState.isPressing ? Color.blue : Color.orange)
.frame(width: 100, height: 100, alignment: .center)
Text("touch me")
}}).simultaneousGesture(press)
}.offset(x: 0, y: 110)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}