SwiftUI - Button Events

Hello all,


i am just in thre process of migrating from UIKit to Swift UI. Now I want to create a simple button where I can just call a function in the button pressed and button released event.


I searched the whole (alomost...) internet but did not find an answer.


Is this not possible with SwiftUI?


Just a simple requirement.


On button press: Call function A

On button release: Call function B


How can I achieve this?


thanks in advance!

Replies

I copy this complete code for showing what you can do with onPress and onLongPress


import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Button(action: {
                print("MyNewPrimitiveButton triggered. Is it printed ?")
            }){ Text("My NEW primitive Button").padding() }
                .buttonStyle(MyNewPrimitiveButtonStyle(color: .yellow))

        }
    }
}
 
struct MyNewPrimitiveButtonStyle: PrimitiveButtonStyle {
    var color: Color

    func makeBody(configuration: PrimitiveButtonStyle.Configuration) -> some View {
        MyButton(configuration: configuration, color: color)
    }
   
    struct MyButton: View {
        @State private var pressed = false

        let configuration: PrimitiveButtonStyle.Configuration
        let color: Color

        var body: some View {

            return configuration.label
                .foregroundColor(.white)
                .padding(15)
                .background(RoundedRectangle(cornerRadius: 5).fill(color))
                .compositingGroup()
                .shadow(color: .black, radius: 3)
                .opacity(self.pressed ? 0.5 : 1.0)
                .scaleEffect(self.pressed ? 0.8 : 1.0)
                .onLongPressGesture(minimumDuration: 2.5, maximumDistance: .infinity, pressing: { pressing in
                withAnimation(.easeInOut(duration: 1.0)) {
                    self.pressed = pressing
                }
                if pressing {
                    print("My long pressed starts")
                    print("     I can initiate any action on start")
                } else {
                    print("My long pressed ends")
                    print("     I can initiate any action on end")
                }
            }, perform: { })
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}



The button can probably be adapted to do exactly what you want (I tried setting animation duration to 100, seems to work pretty well)

Ok thanks for the answer.

i assume that I would have my desired behavior if I set the duration for long press gesture to zero.

is it possible to pass callback functions to the primitive style?

I played with it a bit more.


In fact, animation is not needed.

Idem, you don't need all the effect (even though they may provide interesting feedback in your case)

And the parameter to adjust is minimum duration, with a large value:


        var body: some View {
           
            return configuration.label
                .foregroundColor(.white)
                .padding(15)
                .background(RoundedRectangle(cornerRadius: 5).fill(color))
                .compositingGroup()
                .shadow(color: .black, radius: 3)
                .opacity(self.pressed ? 0.5 : 1.0)
                .scaleEffect(self.pressed ? 0.8 : 1.0)
                .onLongPressGesture(minimumDuration: 100.0, maximumDistance: .infinity, pressing: { pressing in
                    self.pressed = pressing
                    if pressing {
                        print("My long pressed starts")
                        print("     I can initiate any action on start")
                    } else {
                        print("My long pressed ends")
                        print("     I can initiate any action on end")
                    }
                }, perform: { })
        }



is it possible to pass callback functions to the primitive style?

What type of callback do you think of ?

Thanks for the snippet. This helped alot. Regarding callbacks I was thinking of something like this:

Unfortunately, the code does not compile.

Is it possible to extend this Button/Style with additional parameters for callbacks?


import SwiftUI
  
struct ButtonView: View {
    var body: some View {
        VStack {
            Button(actionPressed: {
                print("MyNewPrimitiveButton triggered. Is it printed ?")
            }, actionReleased: { Do something else}){ Text("My NEW primitive Button").padding() }
                .buttonStyle(MyNewPrimitiveButtonStyle(color: .yellow))
  
        }
    }
}
   
struct MyNewPrimitiveButtonStyle: PrimitiveButtonStyle {
    var color: Color
  
    func makeBody(configuration: PrimitiveButtonStyle.Configuration) -> some View {
        MyButton(configuration: configuration, color: color)
    }
     
    struct MyButton: View {
        @State private var pressed = false
  
        let configuration: PrimitiveButtonStyle.Configuration
        let color: Color
        
        let actionPressed
        let actionReleased

        var body: some View {
             
            return configuration.label
                .foregroundColor(.white)
                .padding(15)
                .background(RoundedRectangle(cornerRadius: 5).fill(color))
                .compositingGroup()
                .shadow(color: .black, radius: 3)
                .opacity(self.pressed ? 0.5 : 1.0)
                .scaleEffect(self.pressed ? 0.9 : 1.0)
                .onLongPressGesture(minimumDuration: 2.5, maximumDistance: .infinity, pressing: { pressing in
                    withAnimation(.easeInOut(duration: 0.5)) {
                        self.pressed = pressing
                    }
                    if pressing {
                        print("My long pressed starts")
                        print("     I can initiate any action on start")
                         self.actionPressed()
                    } else {
                        print("My long pressed ends")
                        print("     I can initiate any action on end")
                         self.actionReleased()
                    }
                }, perform: { })
        }
    }
}
  
struct ButtonView_Previews: PreviewProvider {
    static var previews: some View {
        ButtonView()
    }
}
.onLongPressGesture(minimumDuration: 0, pressing: { pressing in
                    if(pressing){
callFunctionA()
                   } else {
callFunctionB()
}
                }){
                  //You can also call function B here
                }