-
-
Save influx6/27bd45328b74e4ea2a4ec66c8bdc07cf to your computer and use it in GitHub Desktop.
SwiftUI Grid Animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
// 1. Use looped H/VStacks to create a grid | |
// 2. Conditionally increase spacing to grow/shrink the grid | |
// 3. Calculate the distance of each dot to the center and use the value to stagger the animation | |
//4. Add random delay on top of the staggered delay value | |
struct ContentView: View { | |
// const & state | |
var dotSize: CGFloat = 4 | |
var gridWidth: Int = 24 | |
var gridHeight: Int = 32 | |
var defaultSpacing: CGFloat = 6 | |
var targetSpacing: CGFloat = 10 | |
@State var animated: Bool = false | |
// computed | |
var spacing: CGFloat { | |
return animated ? targetSpacing : defaultSpacing | |
} | |
// fn | |
// play around with the t argument to speed up or slow down the effect | |
func delay(t: Double, row: Int, col: Int) -> Double { | |
let centerX = gridWidth / 2 | |
let centerY = gridHeight / 2 | |
let distance = sqrt(Double((row - centerY) * (row - centerY) + (col - centerX) * (col - centerX))) | |
return (distance * Double.random(in: 0.1...0.3)) * t | |
} | |
var body: some View { | |
ZStack { | |
Color.black | |
VStack(spacing: spacing) { | |
ForEach(0..<gridHeight, id: \.self) { i in | |
HStack(spacing: spacing) { | |
ForEach(0..<gridWidth, id: \.self) { j in | |
Ellipse() | |
.fill(.white) | |
.frame(width: dotSize, height: dotSize) | |
.opacity(animated ? 0.75 : 0.5) | |
.animation( | |
.interactiveSpring( | |
response: 0.5, | |
dampingFraction: animated ? 0.5 : 0.5) | |
.delay(delay(t: animated ? 0.35 : -10.0, row: i, col: j)), value: animated | |
) | |
} | |
} | |
} | |
} | |
} | |
.gesture( | |
// use DragGesture as a hacky "while touch down" | |
DragGesture(minimumDistance: 0) | |
.onChanged { _ in | |
animated = true | |
} | |
.onEnded { _ in | |
animated = false | |
} | |
) | |
.ignoresSafeArea() | |
} | |
} | |
#Preview { | |
ContentView2() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment