I wanna create a button with SwiftUI that fires the moment my finger touches it (like UIKit's touch down). I also want the opacity of the button to become 0.7 when my finger is pressing the button. When my finger leaves the button, I want the opacity of the button to change back to 1
I've tried 2 different types of button styles to achieve this but both of them failed:
struct ContentView: View {
var body: some View {
Button(action: {
print("action triggered")
}){
Text("Button").padding()
}
.buttonStyle(SomeButtonStyle())
}
}
struct SomeButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.background(Color.green)
.opacity(configuration.isPressed ? 0.7 : 1)
.onLongPressGesture(
minimumDuration: 0,
perform: configuration.trigger//Value of type 'SomeButtonStyle.Configuration' (aka 'ButtonStyleConfiguration') has no member 'trigger'
)
}
}
struct SomePrimativeButtonStyle: PrimitiveButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.background(Color.green)
.opacity(configuration.isPressed ? 0.7 : 1)//Value of type 'SomePrimativeButtonStyle.Configuration' (aka 'PrimitiveButtonStyleConfiguration') has no member 'isPressed'
.onLongPressGesture(
minimumDuration: 0,
perform: configuration.trigger
)
}
}
How should I configure my button style to create such a button?
I do understand your question. I do understand as well present SwiftUI limits !
I defined another button type.
Which seems to get close to what you want.
The key is that a view display must be managed by some state
struct MyPrimitiveButtonStyle: PrimitiveButtonStyle {
var color: Color
func makeBody(configuration: PrimitiveButtonStyle.Configuration) -> some View {
MyButton(configuration: configuration, color: color)
}
struct MyButton: View {
@GestureState private var pressed = false
let configuration: PrimitiveButtonStyle.Configuration
let color: Color
var body: some View {
let longPress = LongPressGesture(minimumDuration: .infinity, maximumDistance: .infinity)
.updating($pressed) { value, state, _ in state = value }
.onEnded { _ in
self.configuration.trigger()
}
return configuration.label
.foregroundColor(.white)
.padding(15)
.background(RoundedRectangle(cornerRadius: 5).fill(color))
.compositingGroup()
.shadow(color: .black, radius: 3)
.opacity(pressed ? 0.5 : 1.0)
.scaleEffect(pressed ? 0.8 : 1.0)
.gesture(longPress)
}
}
}
And another smoother version, with animation (see: https://stackoverflow.com/questions/57252706/animations-triggered-by-events-in-swiftui for details):
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: .infinity, maximumDistance: .infinity, pressing: { pressing in
withAnimation(.easeInOut(duration: 1.0)) {
self.pressed = pressing
}
if pressing {
print("My long pressed starts")
} else {
print("My long pressed ends")
}
}, perform: { })
}
}
}
Thanks to tell if that works for you ; if so, thanks to mark the thread as closed.