Skip to content

Instantly share code, notes, and snippets.

@scalbatty
Created February 14, 2023 19:26
Show Gist options
  • Save scalbatty/7a1b29845022694f3f7fafa343969299 to your computer and use it in GitHub Desktop.
Save scalbatty/7a1b29845022694f3f7fafa343969299 to your computer and use it in GitHub Desktop.
A SwiftUI button style for a toggle button with bouncy touch feedback
struct ContentView: View {
@State var isLiked: Bool = false
var body: some View {
Button {
isLiked.toggle()
} label: {
Image(systemName: isLiked ? "heart.fill" : "heart")
}
.imageScale(.large)
.buttonStyle(LikeButtonStyle(isOn: isLiked))
.tint(.red)
}
}
struct LikeButtonStyle: ButtonStyle {
var isOn: Bool
func makeBody(configuration: Configuration) -> some View {
configuration.label
.foregroundStyle(foregroundStyle)
.animation(nil, value: isOn)
.brightness(brightness(configuration: configuration))
.animation(colorAnimation(configuration: configuration), value: isOn)
.scaleEffect(configuration.isPressed && !isOn ? 0.6 : 1.0)
.animation(scaleAnimation(configuration: configuration), value: isOn)
}
var foregroundStyle: AnyShapeStyle {
if isOn {
return AnyShapeStyle(.tint)
} else {
return AnyShapeStyle(.black)
}
}
func brightness(configuration: Configuration) -> Double {
switch (configuration.isPressed, isOn) {
case (true, true): return 0.8
default: return 0
}
}
func colorAnimation(configuration: Configuration) -> Animation? {
if configuration.isPressed {
return nil
} else {
return .default
}
}
func scaleAnimation(configuration: Configuration) -> Animation? {
switch (configuration.isPressed, isOn) {
case (true, _): return nil
case (false, false):
return .default
case (false, true):
return .spring(response: 0.2, dampingFraction: 0.3)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment