Skip to content

Instantly share code, notes, and snippets.

@LidorFadida
Created January 24, 2025 16:21
Show Gist options
  • Select an option

  • Save LidorFadida/af1f5a0a1ce183490e342c0e600f803d to your computer and use it in GitHub Desktop.

Select an option

Save LidorFadida/af1f5a0a1ce183490e342c0e600f803d to your computer and use it in GitHub Desktop.
//
// Depth-Illusion-Example
//
// Created by Lidor Fadida on 24/01/2025.
//
import SwiftUI
//MARK: - Circle Configuration
struct CircleConfiguration: Identifiable, Hashable {
let id: UUID
let color: Color
init(id: UUID = UUID(), color: Color = .black) {
self.id = id
self.color = color
}
}
//MARK: - Column Configuration Protocol
protocol ColumnsViewConfigurationProtocol {
var circles: [CircleConfiguration] { get }
var offset: CGFloat { get }
var delay: TimeInterval { get }
}
//MARK: - Column Configuration
struct ColumnsViewConfiguration: ColumnsViewConfigurationProtocol {
let circles: [CircleConfiguration]
let offset: CGFloat
let delay: TimeInterval
}
//MARK: - A Column
struct ColumnsView<Configuration: ColumnsViewConfigurationProtocol>: View {
@State private var animate: Bool = false
let configuration: Configuration
var body: some View {
let circles = configuration.circles
let offset = configuration.offset
ZStack {
ForEach(Array(circles.enumerated()), id: \.element) { index, circle in
let width: Double = 5 + (0.4 * Double(circles.count - index))
Circle()
.fill(circle.color.gradient)
.frame(width: width)
.offset(y: animate ? -offset : offset)
.animation(
.easeInOut(duration: 3.0)
.repeatForever(autoreverses: true)
.delay(0.1 * Double(index)),
value: animate
)
}
}
.task {
try? await Task.sleep(for: .seconds(configuration.delay))
animate.toggle()
}
}
}
//MARK: - Example Constants
let numberOfColumns: Int = 30
let colors: [Color] = [.white, .blue, .yellow/* Insert your colors here*/]
let itemsPerColumn = (0..<numberOfColumns).map { i in CircleConfiguration(color: colors[i % colors.count]) }
let inset = 24.0
//MARK: - The Example.
struct PreviewExample: View {
let offset: ((Int) -> CGFloat)
let delay: ((Int) -> TimeInterval)
var body: some View {
HStack(spacing: 5.0) {
ForEach(0..<numberOfColumns, id: \.self) { i in
let configuration = ColumnsViewConfiguration(
circles: itemsPerColumn,
offset: offset(i),
delay: delay(i)
)
ColumnsView(configuration: configuration)
}
}
}
}
#Preview("Wall") {
GeometryReader { proxy in
let size = proxy.size
PreviewExample { _ in
return min(size.width / 2.0, size.height / 2.0) - inset
} delay: { index in
return 0.0
}
.frame(width: proxy.size.width, height: proxy.size.height)
}
.background(Color.black, ignoresSafeAreaEdges: .all)
}
#Preview("Wave") {
GeometryReader { proxy in
let size = proxy.size
PreviewExample { _ in
return min(size.width / 2.0, size.height / 2.0) - inset
} delay: { index in
return 0.1 * Double(index)
}
.frame(width: proxy.size.width, height: proxy.size.height)
}
.background(Color.black, ignoresSafeAreaEdges: .all)
}
#Preview("Cone") {
GeometryReader { proxy in
let size = proxy.size
PreviewExample { index in
let maximumOffset = min(size.width / 2.0, size.height / 2.0) - inset
let offset = maximumOffset - (5.0 * Double(index))
return offset
} delay: { index in
return 0.1 * Double(index)
}
.frame(width: proxy.size.width, height: proxy.size.height)
.rotationEffect(.degrees(90))
}
.background(Color.black, ignoresSafeAreaEdges: .all)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment