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

16

76

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 SwiftUI?

Here is the simple code for the button I have now (handles only the "normal" tap/touch case).

Button(action: {self.BLEinfo.startScan() }) {
                        Text("Scan")
                    } .disabled(self.BLEinfo.isScanning)

I already tried to add a "longPress gesture" but it still only "executes" the "normal/short" click. This was the code I tried:

Button(action: {self.BLEinfo.startScan() }) {
                        Text("Scan")
                            .fontWeight(.regular)
                            .font(.body)
                        .gesture(
                            LongPressGesture(minimumDuration: 2)
                                .onEnded { _ in
                                    print("Pressed!")
                            }
                        )
                    }

Thanks!

Gerard

Phene answered 8/10, 2019 at 10:56 Comment(1)
I fixed this with a custom UIScrollView and a custom UIView: gist.github.com/danhalliday/79b003d1cdbb84069c5c9f24fe069827Ichnography
P
64

I tried many things but finally I did something like this:

    Button(action: {
    }) {
        VStack {
            Image(self.imageName)
                .resizable()
                .onTapGesture {
                    self.action(false)
                }
                .onLongPressGesture(minimumDuration: 0.1) {
                    self.action(true)
                }
        }
    }

It is still a button with effects but short and long press are different.

Prussiate answered 31/10, 2019 at 12:57 Comment(2)
Please note that as of Xcode 11.2.1 / iOS 13.2 the order seems to be important here. Using onLongPressGesture() before onTapGesture() will ignore the latter one.Coiffeur
this does not have the animation of tapping or pressing and blocking the code in actionWarfold
N
62

Combining a high priority gesture and a simultaneous gesture should do the trick.

Button(action: {}) {
    Text("A Button")
}
    .simultaneousGesture(
        LongPressGesture()
            .onEnded { _ in
                print("Loooong")
            }
    )
    .highPriorityGesture(
        TapGesture()
            .onEnded { _ in
                print("Tap")
            }
    )

Found this a handy pattern when interacting with other views as well.

Nidify answered 9/3, 2021 at 0:12 Comment(5)
This solution also works inside a ScrollView :) Thanks.Gangling
This works fine on iOS, but does not seem to work on macOS. Neither gesture is recognized with Xcode Version 13.3.1 (13E500a).Joceline
This seems to get rid of the button animation when tapping, at least as of iOS 16.4. Do you know how to avoid that?Deloresdeloria
While functionally it solves the problem, this approach has the disadvantage that the button doesn't animate properly on a tap anymore (if you're using a button style that animates the button, e.g. shrinking it while it's pressed). I'm under the impression that the touches are delayed with this setup, so the tap is only registered a like 0.1 seconds later or something, causing a rather ugly tap animation on the button (if you have any), as it starts and end abruptly and doesn't give the user a feeling of responsiveness.Commie
It also is bad for accessibility - keyboard users need special implementations with thisPegeen
A
14

(Later, in 2023…)

I tried all the solutions I could find for something similar, but every solution produced some sort of conflict where one gesture prevented the other, or something like that.

On my own, I decided to implement a type conforming to PrimitiveButtonStyle after reading in the documentation:

Specify a style that conforms to PrimitiveButtonStyle to create a button with custom interaction behavior.

In essence, the style uses onTapGesture and onLongPressGesture, but all the "tap gesture" does is uses the protocol's exposed configuration variable to activate the button's "action" as defined when declaring it.

As a bonus, the long press gesture's pressed variable can be used to decide whether to show custom feedback indicating the button is being pressed, regardless of which gesture ends up succeeding.

// Conform to `PrimitiveButtonStyle` for custom interaction behaviour

struct SupportsLongPress: PrimitiveButtonStyle {
    
    /// An action to execute on long press
    let longPressAction: () -> ()
    
    /// Whether the button is being pressed
    @State var isPressed: Bool = false
    
    func makeBody(configuration: Configuration) -> some View {
        
        // The "label" as specified when declaring the button
        configuration.label
        
            // Visual feedback that the button is being pressed
            .scaleEffect(self.isPressed ? 0.9 : 1.0)
        
            .onTapGesture {
                
                // Run the "action" as specified
                // when declaring the button
                configuration.trigger()
                
            }
        
            .onLongPressGesture(
                
                perform: {
                    
                    // Run the action specified
                    // when using this style
                    self.longPressAction()
                    
                },
                
                onPressingChanged: { pressing in
                    
                    // Use "pressing" to infer whether the button
                    // is being pressed
                    self.isPressed = pressing
                    
                }
                
            )
        
    }
    
}

/// A modifier that applies the `SupportsLongPress` style to buttons
struct SupportsLongPressModifier: ViewModifier {
    let longPressAction: () -> ()
    func body(content: Content) -> some View {
        content.buttonStyle(SupportsLongPress(longPressAction: self.longPressAction))
    }
}

/// Extend the View protocol for a SwiftUI-like shorthand version
extension View {
    func supportsLongPress(longPressAction: @escaping () -> ()) -> some View {
        modifier(SupportsLongPressModifier(longPressAction: longPressAction))
    }
}

// --- At the point of use:

struct MyCustomButtonRoom: View {
    
    var body: some View {
        
        Button(
            action: {
                print("You've tapped me!")
            },
            label: {
                Text("Do you dare interact?")
            }
        )
        .supportsLongPress {
            print("Looks like you've pressed me.")
        }
        
    }
    
}
Annadiane answered 6/6, 2023 at 8:12 Comment(5)
This solution works best 2023 and onwards. Btw, not just for buttons but also for NavigationLinksCondenser
Great work, Steve! Excellent solution that provides the framework to further customize button gestures!Illhumored
If you want a tap effect that is more similar to the stock effect use .brightness(self.isPressed ? 0.1 : 0) rather than .scaleEffect(self.isPressed ? 0.9 : 1.0)Novelette
That's a nice approach. Unfortunately, the long press gesture takes quite long to trigger and even when you specify a shorter minimumDuration that doesn't change. It seems like SwiftUI first gives the stage to the tap gesture and "waits" until it's done "with its performance" (either it triggered or it said "I won't trigger, it took too long") before it gives the stage to the long-press gesture. That's the only thing that keeps me from using this approach.Commie
Mischa – I think you're right. That seems to be the case with any combination of a tap gesture with a long press gesture (it's not specifically the involvement of a PrimitiveButtonStyle).Annadiane
A
12

I just discovered that the effect depends on the order of the implementation. Implementing the detection of gestures in the following order it seems to be possible to detect and identify all three gestures:

  1. handle a double tap gesture
  2. handle a longPressGesture
  3. handle a single tap gesture

Tested on Xcode Version 11.3.1 (11C504)

    fileprivate func myView(_ height: CGFloat, _ width: CGFloat) -> some View {
    return self.textLabel(height: height, width: width)
        .frame(width: width, height: height)
        .onTapGesture(count: 2) {
            self.action(2)
        }
        .onLongPressGesture {
            self.action(3)
        }
        .onTapGesture(count: 1) {
            self.action(1)
        }
}
Autumn answered 9/2, 2020 at 15:57 Comment(0)
G
6

Here is my implementation using a modifier:

struct TapAndLongPressModifier: ViewModifier {
  @State private var isLongPressing = false
  let tapAction: (()->())
  let longPressAction: (()->())
  func body(content: Content) -> some View {
    content
      .scaleEffect(isLongPressing ? 0.95 : 1.0)
      .onLongPressGesture(minimumDuration: 1.0, pressing: { (isPressing) in
        withAnimation {
          isLongPressing = isPressing
          print(isPressing)
        }
      }, perform: {
        longPressAction()
      })
      .simultaneousGesture(
        TapGesture()
          .onEnded { _ in
            tapAction()
          }
      )
  }
}

Use it like this on any view:

.modifier(TapAndLongPressModifier(tapAction: { <tap action> },
                                  longPressAction: { <long press action> }))

It just mimics the look a button by scaling the view down a bit. You can put any other effect you want after scaleEffect to make it look how you want when pressed.

Geomancy answered 1/12, 2020 at 18:58 Comment(1)
This only worked for the tapAction, the longPressAction was never called in my case (Xcode 13.1)Naashom
J
5

I had to do this for an app I am building, so just wanted to share. Refer code at the bottom, it is relatively self explanatory and sticks within the main elements of SwiftUI.

The main differences between this answer and the ones above is that this allows for updating the button's background color depending on state and also covers the use case of wanting the action of the long press to occur once the finger is lifted and not when the time threshold is passed.

As noted by others, I was unable to directly apply gestures to the Button and had to apply them to the Text View inside it. This has the unfortunate side-effect of reducing the 'hitbox' of the button, if I pressed near the edges of the button, the gesture would not fire. Accordingly I removed the Button and focused on manipulating my Text View object directly (this can be replaced with Image View, or other views (but not Button!)).

The below code sets up three gestures:

  1. A LongPressGesture that fires immediately and reflects the 'tap' gesture in your question (I haven't tested but this may be able to replaced with the TapGesture)

  2. Another LongPressGesture that has a minimum duration of 0.25 and reflect the 'long press' gesture in your question

  3. A drag gesture with minimum distance of 0 to allow us to do events at the end of our fingers lifting from the button and not automatically at 0.25 seconds (you can remove this if this is not your use case). You can read more about this here: How do you detect a SwiftUI touchDown event with no movement or duration?

We sequence the gestures as follows: Use 'Exclusively' to combine the "Long Press" (i.e. 2 & 3 above combined) and Tap (first gesture above), and if the 0.25 second threshold for "Long Press" is not reached, the tap gesture is executed. The "Long Press" itself is a sequence of our long press gesture and our drag gesture so that the action is only performed once our finger is lifted up.

I also added code in the below for updating the button's colours depending on the state. One small thing to note is that I had to add code on the button's colour into the onEnded parts of the long press and drag gesture because the minuscule processing time would unfortunately result in the button switching back to darkButton colour between the longPressGesture and the DragGesture (which should not happen theoretically, unless I have a bug somewhere!).

You can read more here about Gestures: https://developer.apple.com/documentation/swiftui/gestures/composing_swiftui_gestures

If you modify the below and pay attention to Apple's notes on Gestures (also this answer was useful reading: How to fire event handler when the user STOPS a Long Press Gesture in SwiftUI?) you should be able to set up complex customised button interactions. Use the gestures as building blocks and combine them to remove any deficiency within individual gestures (e.g. longPressGesture does not have an option to do the events at its end and not when the condition is reached).

P.S. I have a global environment object 'dataRouter' (which is unrelated to the question, and just how I choose to share parameters across my swift views), which you can safely edit out.

struct AdvanceButton: View {

@EnvironmentObject var dataRouter: DataRouter

@State var width: CGFloat
@State var height: CGFloat
@State var bgColor: Color

@GestureState var longPress = false
@GestureState var longDrag = false

var body: some View {

    let longPressGestureDelay = DragGesture(minimumDistance: 0)
        .updating($longDrag) { currentstate, gestureState, transaction in
                gestureState = true
        }
    .onEnded { value in
        print(value.translation) // We can use value.translation to see how far away our finger moved and accordingly cancel the action (code not shown here)
        print("long press action goes here")
        self.bgColor = self.dataRouter.darkButton
    }

    let shortPressGesture = LongPressGesture(minimumDuration: 0)
    .onEnded { _ in
        print("short press goes here")
    }

    let longTapGesture = LongPressGesture(minimumDuration: 0.25)
        .updating($longPress) { currentstate, gestureState, transaction in
            gestureState = true
    }
    .onEnded { _ in
        self.bgColor = self.dataRouter.lightButton
    }

    let tapBeforeLongGestures = longTapGesture.sequenced(before:longPressGestureDelay).exclusively(before: shortPressGesture)

    return
        Text("9")
            .font(self.dataRouter.fontStyle)
            .foregroundColor(self.dataRouter.darkButtonText)
            .frame(width: width, height: height)
            .background(self.longPress ? self.dataRouter.lightButton : (self.longDrag ? self.dataRouter.brightButton : self.bgColor))
            .cornerRadius(15)
            .gesture(tapBeforeLongGestures)

    }

}
Jubilation answered 22/5, 2020 at 19:17 Comment(2)
Thank you, you are amazing 🥳Consumptive
Thank you so much, this is the exact behavior I was looking for. Also, I can confirm that, at least in my case, using a TapGesture does not workRomie
T
2

This isn't tested, but you can try to add a LongPressGesture to your button.

It'll presumably look something like this.

struct ContentView: View {
    @GestureState var isLongPressed = false

    var body: some View {
        let longPress = LongPressGesture()
            .updating($isLongPressed) { value, state, transaction in
                state = value
            }

        return Button(/*...*/)
            .gesture(longPress)
    }
}
Tildie answered 8/10, 2019 at 12:38 Comment(1)
Hi Kilian Actually I should have mentioned that I had already tried adding a longPress gesture but it will still only "execute" the "normal click" action and not the long press. Will edit my post to add that (as you are the 2nd person to suggest that - the first one deleted his answer).Phene
C
2

As a follow up, I had the same issue and I tried all of these answers but didn't like how they all worked.

I ended up using a .contextMenu it was way easier and produces pretty much the same effect. Check link here and here is an example

UPDATE: As of iOS 16, .contextMenu has been depreciated. So I ended up using .simultaneousGesture on the Button, not the content in the button's label block.

i.e.

Button {
        // handle Button Tap
    } label: {
        // button label content here
    }
    .simultaneousGesture(LongPressGesture()
        .onEnded { _ in
            // handle long press here
        }
    )

This still preserves the button animations as well.
Note tested before iOS 16 however.

Chantal answered 29/10, 2020 at 0:52 Comment(2)
This will cause the list not to scrollPodite
Hey @gaohomway, yes, but did you find another workaround?Edibles
M
2

Kevin's answer was the closest to what I needed. Since ordering the longPressGesture before the tapGesture broke ScrollViews for me, but the inverse made the minimumDuration parameter do nothing, I implemented the long press functionality myself:

struct TapAndLongPressModifier: ViewModifier {
    @State private var canTap = false
    @State private var pressId = 0
    let tapAction: (()->())
    let longPressAction: (()->())
    var minimumDuration = 1.0
    func body(content: Content) -> some View {
        content
            .onTapGesture {
                if canTap {
                    tapAction()
                }
            }
            .onLongPressGesture(
                minimumDuration: 1.0,
                pressing: { (isPressing) in
                    pressId += 1
                    canTap = isPressing
                    if isPressing {
                        let thisId = pressId
                        
                        DispatchQueue.main.asyncAfter(deadline: .now() + minimumDuration) {
                            if thisId == pressId {
                                canTap = false
                                longPressAction()
                            }
                        }
                    }
                },
                
                // We won't actually use this
                perform: {}
            )
    }
}
Mathura answered 17/9, 2021 at 2:12 Comment(0)
B
1

Thought I'd post back on this, in case anyone else is struggling. Strange that Apple's default behaviour works on most controls but not buttons. In my case I wanted to keep button effects while supporting long press.

An approach that works without too much complexity is to ignore the default button action and create a simultaneous gesture that handles both normal and long clicks.

In your view you can apply a custom long press modifier like this:

var body: some View {

        // Apply the modifier
        Button(action: self.onReloadDefaultAction) {
            Text("Reload")
        }
            .modifier(LongPressModifier(
                isDisabled: self.sessionButtonsDisabled,
                completionHandler: self.onReloadPressed))
    }

    // Ignore the default click
    private func onReloadDefaultAction() {
    }

    // Handle the simultaneous gesture
    private func onReloadPressed(isLongPress: Bool) {

        // Do the work here
    }

My long press modifier implementation looked like this and uses the drag gesture that I found from another post. Not very intuitive but it works reliably, though of course I would prefer not to have to code this plumbing myself.

struct LongPressModifier: ViewModifier {

    // Mutable state
    @State private var startTime: Date?

    // Properties
    private let isDisabled: Bool
    private let longPressSeconds: Double
    private let completionHandler: (Bool) -> Void

    // Initialise long press behaviour to 2 seconds
    init(isDisabled: Bool, completionHandler: @escaping (Bool) -> Void) {

        self.isDisabled = isDisabled
        self.longPressSeconds = 2.0
        self.completionHandler = completionHandler
    }

    // Capture the start and end times
    func body(content: Content) -> some View {

        content.simultaneousGesture(DragGesture(minimumDistance: 0)
            .onChanged { _ in

                if self.isDisabled {
                    return
                }

                // Record the start time at the time we are clicked
                if self.startTime == nil {
                    self.startTime = Date()
                }
            }
            .onEnded { _ in

                if self.isDisabled {
                    return
                }

                // Measure the time elapsed and reset
                let endTime = Date()
                let interval = self.startTime!.distance(to: endTime)
                self.startTime = nil

                // Return a boolean indicating whether a normal or long press
                let isLongPress = !interval.isLess(than: self.longPressSeconds)
                self.completionHandler(isLongPress)
            })
    }
}
Bronson answered 10/5, 2020 at 21:24 Comment(0)
E
1

just do this: the first modifier should be onLongPressGesture(minumumDuration: (the duration you want)) and the following mondifier should be onLongPressGesture(minimumDuration: 0.01) <- or some other super small numbers

this works for me perfectly

Empale answered 26/7, 2021 at 15:19 Comment(0)
M
1

!! If you need to press and hold gesture just to pop up the menu, consider using it (even work great on Vision Pro)

Menu(content: {
    //The menu items you want to show when long press
    Button("Add", action: {})
    Button("Delete", action: {})
}, label: {
    Text("I am a item")
}, primaryAction: {
    //The tap gesture action
})
Mont answered 25/8, 2023 at 9:41 Comment(0)
H
1

Perhaps my method will help you. Tested on Xcode 15 and iOS 17.1. ScrollView() is not blocked.

struct MultiTapButton<Label> : View where Label : View {
    
    let label: Label
    let singleTapAction: () -> Void
    let doubleTapAction: () -> Void
    let longPressAction: () -> Void
    let duration: Double
     
    init(singleTapAction: @escaping () -> Void, doubleTapAction: @escaping () -> Void, longPressAction: @escaping () -> Void, duration: Double, @ViewBuilder label: () -> Label) {
        self.label = label()
        self.singleTapAction = singleTapAction
        self.doubleTapAction = doubleTapAction
        self.longPressAction = longPressAction
        self.duration = duration
    }
    
    @GestureState private var onPressing: Bool = false
    @State var longAction: Bool = false
    
    var gesture: some Gesture {
            LongPressGesture(minimumDuration: duration)
                .updating($onPressing) { currentState, gestureState, transaction in
                    gestureState = currentState
                    transaction.animation = Animation.spring(duration: 0.0625)
                }
                .onEnded { finished in
                    longAction = true
                    longPressAction()
                }
        }
     
    var body: some View {
        Button(action: {
            if longAction {
                longAction = false
                return
            }
            singleTapAction()
        }) {
            label
        }
        .simultaneousGesture(gesture)
        .highPriorityGesture(
            TapGesture(count: 2)
                .onEnded { _ in
                    doubleTapAction()
                }
        )
    }
}

Example:

struct ExampleView: View {
    
    let gridItems = [GridItem(.fixed(120), spacing: 2), GridItem(.fixed(120), spacing: 2), GridItem(.fixed(120), spacing: 2)]
    
    var body: some View {
        ZStack(){
            Color.orange
            ScrollView(showsIndicators: true){
                LazyVGrid(columns: gridItems, alignment: .center, spacing: 2) {
                    ForEach(0..<24) { index in
                        MultiTapButton(singleTapAction: {
                            print("Single Tap Action")
                        }, doubleTapAction: {
                            print("Double Tap Action")
                        }, longPressAction: {
                            print("Long Press Action")
                        }, duration: 0.5) {
                            Rectangle()
                                .foregroundStyle(Color.purple)
                                .frame(width: 120, height: 150, alignment: .center)
                        }
                    }
                }
                .padding(.vertical, 64)
            }
        }
        .ignoresSafeArea()
    }
}
Hoyos answered 8/11, 2023 at 19:39 Comment(0)
K
1

You can make a UIViewRepresentable that has the long press gesture, then use it as an overlay with the button.

Button {
// regular button action
} label: {
  Text("Normal Button")
}
.overlay {
  LongPressGestureView {
  // your long press action here
  }
}
struct LongPressGestureView: UIViewRepresentable {
    let action: () -> Void
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: .zero)
        view.backgroundColor = .clear
        let longPressGesture = UILongPressGestureRecognizer(
            target: context.coordinator,
            action: #selector(Coordinator.handleLongPress)
        )
        view.addGestureRecognizer(longPressGesture)
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) { }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(action: action)
    }
    
    class Coordinator: NSObject {
        let action: () -> Void
        
        init(action: @escaping () -> Void) {
            self.action = action
        }
        
        @objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
            if gesture.state == .began {
                action()
            }
        }
    }
}
Kelwunn answered 14/4, 2024 at 11:15 Comment(0)
I
0

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

Insincere answered 2/7, 2020 at 12:30 Comment(0)
R
0

This is the pattern for recognizing the tap or long pressing gesture:

...
@State var buttonClicked = false // Its true when the button click detected. It should be make false after processed in another func.
@State var buttonLongPressed = false // Its true as long as the button pressed, otherwise false.
@State var tap_01 = false  // Auxilary variable
@State var tap_02 = false  // Auxilary variable
...

Button(action: {
    // When the tap is UP
    print("Button long pressed ends here if it started")
    self.buttonLongPressed = false
    if ((self.tap_02 == true) && ((self.tap_01 == true))) {
        self.buttonClicked = false
        print("All gestures end here")
    } else {
        self.buttonClicked = true
        print("Button clicked...  if the button has not been long pressed")
    }
    self.tap_01 = false
    self.tap_02 = false
    
}, label: {
    Text("LABEL")
})
.simultaneousGesture(
    // When the tap is UP
    LongPressGesture().onEnded({ _ in
        self.tap_01 = true
        
        if (self.tap_02 == true) {
            self.buttonLongPressed = true
            print("Button long pressed starts here")
        }
    })
)
.simultaneousGesture(
    // When the long press detected
    LongPressGesture().onChanged({ _ in
        print("Button gestures starts here")
        self.tap_02 = true
    })
)
Renault answered 18/1, 2024 at 9:12 Comment(1)
Please explain how your solution works. There are 4 undefined variables.Nowhere

© 2022 - 2025 — McMap. All rights reserved.