Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI run code periodically while button is being held down; run different code when it is just tapped?

What I'm trying to do is implement a button that runs a certain line of code every 0.5 seconds while it is being held down (it can be held down indefinitely and thus run the print statement indefinitely). I'd like it to have a different behavior when it is tapped. Here is the code:

struct ContentView: View {
@State var timeRemaining = 0.5
let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
@State var userIsPressing = false //detecting whether user is long pressing the screen

var body: some View {
    VStack {
       Image(systemName: "chevron.left").onReceive(self.timer) { _ in
           if self.userIsPressing == true {
             if self.timeRemaining > 0 {
                self.timeRemaining -= 0.5
              }
            //resetting the timer every 0.5 secdonds and executing code whenever //timer reaches 0

     if self.timeRemaining == 0 {
            print("execute this code")
            self.timeRemaining = 0.5
         }
        }
    }.gesture(LongPressGesture(minimumDuration: 0.5)
                   .onChanged() { _ in
                       //when longpressGesture started
                   self.userIsPressing = true
                   }
                   .onEnded() { _ in
                       //when longpressGesture ended
                   self.userIsPressing = false

                   }
                   )
           }
}
}

At the moment, it's sort of reverse of what I need it to do; the code above runs the print statement indefinitely when I click the button once but when I hold it down, it only does the execution once...how can I fix this?

like image 922
nickcoding Avatar asked Jan 29 '26 20:01

nickcoding


1 Answers

Here is a solution - to get continuous pressing it needs to combine long press gesture with sequenced drag and add timer in handlers.

Updated: Tested with Xcode 11.4 / iOS 13.4 (in Preview & Simulator)

struct TimeEventGeneratorView: View {
    var callback: () -> Void
    private let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()

    var body: some View {
        Color.clear
            .onReceive(self.timer) { _ in
                self.callback()
            }
    }
}

struct TestContinuousPress: View {

    @GestureState var pressingState = false // will be true till tap hold
    var pressingGesture: some Gesture {
        LongPressGesture(minimumDuration: 0.5).sequenced(before:
              DragGesture(minimumDistance: 0, coordinateSpace:
              .local)).updating($pressingState) { value, state, transaction in
                switch value {
                    case .second(true, nil):
                        state = true
                    default:
                        break
                }
            }.onEnded { _ in
            }
    }

    var body: some View {
        VStack {
            Image(systemName: "chevron.left")
                .background(Group { if self.pressingState { TimeEventGeneratorView {
                    print(">>>> pressing: \(Date())")
                }}})
            .gesture(TapGesture().onEnded {
                print("> just tap ")
            })
            .gesture(pressingGesture)
        }
    }
}
like image 82
Asperi Avatar answered Feb 01 '26 18:02

Asperi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!