Skip to content

Instantly share code, notes, and snippets.

@timi2506
Created February 26, 2026 15:53
Show Gist options
  • Select an option

  • Save timi2506/1b65f1d0f2812bc812ad2b370e7af627 to your computer and use it in GitHub Desktop.

Select an option

Save timi2506/1b65f1d0f2812bc812ad2b370e7af627 to your computer and use it in GitHub Desktop.
CoverFlip

Feel free to use this in your Projects :D

If you like what i do feel free to support me :)

//
// CoverFlip.swift
// CoverFlip
//
// Created by Tim on 26.02.26.
//
import SwiftUI
struct CoverFlipTransition: AnimatableModifier {
var progress: Double
var isInsertion: Bool
var blurStrength: CGFloat = 3.5
var animatableData: Double {
get { progress }
set { progress = newValue }
}
func body(content: Content) -> some View {
let angle = isInsertion ? (180 - 180 * progress) : (0 - 180 * progress)
let blurAmount = blurForAngle(angle)
return content
.rotation3DEffect(
.degrees(angle),
axis: (x: 0, y: 1, z: 0),
perspective: 0.7
)
.blur(radius: blurAmount)
.opacity(abs(angle) > 90 ? 0 : 1)
}
private func blurForAngle(_ angle: Double) -> CGFloat {
let normalized = min(abs(angle) / 90, 1)
return CGFloat(normalized * blurStrength)
}
}
extension AnyTransition {
static func coverFlip(blurStrength: CGFloat = 3.5) -> AnyTransition {
.asymmetric(
insertion: .modifier(
active: CoverFlipTransition(progress: 0, isInsertion: true, blurStrength: blurStrength),
identity: CoverFlipTransition(progress: 1, isInsertion: true, blurStrength: blurStrength)
),
removal: .modifier(
active: CoverFlipTransition(progress: 1, isInsertion: false, blurStrength: blurStrength),
identity: CoverFlipTransition(progress: 0, isInsertion: false, blurStrength: blurStrength)
)
)
}
}
#Preview {
Showcase()
}
struct Showcase: View {
@State var yes = false
@State var duration: CGFloat = 0.75
@State var blurStrength: CGFloat = 3.5
let cornerRadius: CGFloat = 25
let frame = CGSize(width: 350, height: 350)
var body: some View {
Spacer()
ZStack {
if yes {
Rectangle()
.foregroundStyle(.red)
.cornerRadius(cornerRadius)
.frame(width: frame.width, height: frame.height)
.transition(.coverFlip(blurStrength: blurStrength))
} else {
Rectangle()
.foregroundStyle(.blue)
.cornerRadius(cornerRadius)
.frame(width: frame.width, height: frame.height)
.transition(.coverFlip(blurStrength: blurStrength))
}
}
.animation(.easeInOut(duration: duration), value: yes)
Spacer()
VStack {
Toggle("Slow", isOn: Binding(get: {
duration != 0.75
}, set: { value in
if value {
duration = 7.5
} else {
duration = 0.75
}
}))
Slider(value: $blurStrength, in: 0...10) {
Text("Blur Strength")
}
if #available(iOS 26.0, *) {
Button(action: {
yes.toggle()
}) {
HStack {
Spacer()
Text("Toggle")
.bold()
Spacer()
}
.padding(10)
}
.buttonStyle(.glassProminent)
} else {
Button(action: {
yes.toggle()
}) {
HStack {
Spacer()
Text("Toggle")
.bold()
Spacer()
}
.padding(10)
}
.buttonStyle(.borderedProminent)
}
}
.padding()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment