Skip to content

Instantly share code, notes, and snippets.

@DaemonLoki
Created July 12, 2022 20:01
Show Gist options
  • Save DaemonLoki/98b1f462432a6f25e91ea77d19b96d39 to your computer and use it in GitHub Desktop.
Save DaemonLoki/98b1f462432a6f25e91ea77d19b96d39 to your computer and use it in GitHub Desktop.
Card Flip Animation with a drag.
import SwiftUI
struct ViewContainer: View {
var flipped: Bool
var isReversed: Bool
var body: some View {
if flipped {
ZStack {
RoundedRectangle(cornerRadius: 20, style: .continuous)
.fill(.blue)
Text("Number 1")
.font(.largeTitle)
}
.rotation3DEffect(.degrees(isReversed ? 180 : 0), axis: (x: 0, y: 1, z: 0))
} else {
ZStack {
RoundedRectangle(cornerRadius: 20, style: .continuous)
.fill(.green)
Text("Darn, it works just like that.")
}
.rotation3DEffect(.degrees(!flipped && !isReversed ? 180 : 0), axis: (x: 0, y: 1, z: 0))
}
}
}
struct ContentView: View {
@State private var flipped = false
@State private var startFlipped = false
@State private var dragAmount: Double = 0
let animationDuration = 0.4
@State private var isReversed = true
var body: some View {
ViewContainer(flipped: flipped, isReversed: isReversed)
.frame(width: 300, height: 300, alignment: .center)
.rotation3DEffect(.degrees(dragAmount), axis: (x: 0, y: 1, z: 0))
.gesture(
DragGesture()
.onChanged({ dragValue in
if !flipped && !startFlipped {
isReversed = true
}
dragAmount = dragValue.translation.width
if abs(dragAmount.truncatingRemainder(dividingBy: 270)) > 90 {
flipped = startFlipped ? false : true
} else {
flipped = startFlipped ? true : false
}
})
.onEnded({ dragValue in
withAnimation(.easeOut(duration: animationDuration)) {
if dragAmount > 270 {
dragAmount = 360
startFlipped = false
} else if dragAmount < -270 {
dragAmount = -360
startFlipped = false
} else if dragAmount > 90 {
dragAmount = 180
startFlipped = !startFlipped
} else if dragAmount < -90 {
dragAmount = -180
startFlipped = !startFlipped
} else {
dragAmount = 0
}
}
// That's the hack. Putting it to 0 as quiet as leaving the room after the baby sleeps.
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
dragAmount = 0
if startFlipped && flipped {
isReversed = false
} else if !flipped && !isReversed && !startFlipped {
isReversed = true
}
}
})
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment