SwiftUI: how to handle BOTH tap & long press of button?

前端 未结 8 1212
刺人心
刺人心 2020-12-15 06:59

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

8条回答
  •  一向
    一向 (楼主)
    2020-12-15 07:41

    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()
        }
    }
    
    

提交回复
热议问题