Skip to content

Instantly share code, notes, and snippets.

@marcusficner
Created June 22, 2022 20:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcusficner/ef211ee16773fb5d18ff20443cef7375 to your computer and use it in GitHub Desktop.
Save marcusficner/ef211ee16773fb5d18ff20443cef7375 to your computer and use it in GitHub Desktop.
Magical 3D Button in SwiftUI
//
// ContentView.swift
// Magical3DButton
//
// Created by Marcus Ficner on 22.06.22.
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Magical3DButton()
Spacer()
}
.padding()
}
}
struct Magical3DButton: View {
@State var offset: Double = 0
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color(uiColor: UIColor(red: 0.64, green: 0.00, blue: 0.21, alpha: 1.00)))
.offset(x: 0, y: 4)
.shadow(color: Color.init(white: 0.5, opacity: 0.5), radius: 1, x: 0, y: 3 - offset)
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color(uiColor: UIColor(red: 0.93, green: 0.00, blue: 0.23, alpha: 1.00)))
Text("Push Me")
.bold()
.foregroundColor(Color.white)
}
.offset(x: 0, y: offset)
}
.animation(.spring(response: 0.2, dampingFraction: 0.525, blendDuration: 0), value: offset)
.onTouchDownUp(pressed: { pressed in
withAnimation {
offset = pressed ? 3 : 0
}
})
.frame(width: 120, height: 44)
.padding()
}
}
// MARK: - Handle touch down event
// https://betterprogramming.pub/implement-touch-events-in-swiftui-b3a2b0700fd4#
extension View {
/// A convenience method for applying `TouchDownUpEventModifier.`
func onTouchDownUp(pressed: @escaping ((Bool) -> Void)) -> some View {
self.modifier(TouchDownUpEventModifier(pressed: pressed))
}
}
struct TouchDownUpEventModifier: ViewModifier {
/// Keep track of the current dragging state. To avoid using `onChange`, we won't use `GestureState`
@State var dragged = false
/// A closure to call when the dragging state changes.
var pressed: (Bool) -> Void
func body(content: Content) -> some View {
content
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { _ in
if !dragged {
dragged = true
pressed(true)
}
}
.onEnded { _ in
dragged = false
pressed(false)
}
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewLayout(.sizeThatFits)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment