What You Will Build
A premium-looking card with a rainbow holographic overlay that shifts as you drag your finger across it. The card also tilts in 3D space, creating a realistic trading-card hologram effect. This is used in digital wallets, collectible card UIs, and premium membership screens.
Why This Pattern Matters
Holographic card effects communicate value and exclusivity. Apple Wallet uses similar 3D tilt effects on credit cards. This tutorial teaches you how to combine rotation3DEffect with dynamic gradient positioning driven by gesture state.
Key SwiftUI Concepts
- rotation3DEffect for tilting the card on X and Y axes based on drag offset.
- LinearGradient with dynamic UnitPoints that shift based on finger position.
- .blendMode(.overlay) to mix the rainbow gradient with the dark card base.
Step 1: The Card Base with Holographic Overlay
Start with a black rounded rectangle and overlay a multi-color gradient that uses the drag offset to shift its start and end points:
struct BasicHolographDemo: View {
@State private var dragOffset: CGSize = .zero
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 20)
.fill(.black)
.frame(width: 280, height: 380)
.overlay {
RoundedRectangle(cornerRadius: 20)
.fill(
LinearGradient(
colors: [
.blue.opacity(0.5),
.purple.opacity(0.5),
.pink.opacity(0.5),
.orange.opacity(0.5),
.green.opacity(0.5),
],
startPoint: UnitPoint(
x: 0.5 + dragOffset.width / 500,
y: 0 + dragOffset.height / 500
),
endPoint: UnitPoint(
x: 0.5 - dragOffset.width / 500,
y: 1 - dragOffset.height / 500
)
)
)
.blendMode(.overlay)
}
.overlay {
VStack {
HStack {
Text("HOLOGRAPHIC")
.font(.caption.bold())
.foregroundStyle(.white.opacity(0.7))
Spacer()
Image(systemName: "sparkles")
.foregroundStyle(.white.opacity(0.7))
}
Spacer()
HStack {
Text("PREMIUM CARD")
.font(.headline)
.foregroundStyle(.white)
Spacer()
}
}
.padding(20)
}
.shadow(color: .purple.opacity(0.3), radius: 20, y: 10)
}
}
}
Step 2: Add 3D Rotation and Drag Gesture
Apply two rotation3DEffect modifiers that tilt the card based on drag translation, then spring back when the finger lifts:
.rotation3DEffect(
.degrees(Double(dragOffset.width) / 15),
axis: (x: 0, y: 1, z: 0)
)
.rotation3DEffect(
.degrees(Double(-dragOffset.height) / 15),
axis: (x: 1, y: 0, z: 0)
)
.gesture(
DragGesture()
.onChanged { value in dragOffset = value.translation }
.onEnded { _ in
withAnimation(.spring) { dragOffset = .zero }
}
)
How the Gradient Shift Works
The gradient start and end UnitPoints are centered at (0.5, 0) and (0.5, 1). Dividing the drag offset by 500 creates a subtle shift. When you drag right, the gradient start moves right while the end moves left, creating a rainbow sweep across the card surface.
Tips and Pitfalls
- Divisor controls sensitivity: Dividing by 500 gives subtle movement. Use 200 for a more dramatic shift.
- .blendMode(.overlay) is key: it mixes colors with the black base, creating the holographic sheen without washing out the card content.
- Spring animation on release makes the card snap back naturally instead of jumping.
- Shadow follows tilt: For extra realism, adjust the shadow offset based on dragOffset too.
iOS Version: iOS 15+