Skip to content

Instantly share code, notes, and snippets.

@izakpavel
Created January 21, 2021 05:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save izakpavel/8702b141e0d14ecf4d14654369fc9d06 to your computer and use it in GitHub Desktop.
Save izakpavel/8702b141e0d14ecf4d14654369fc9d06 to your computer and use it in GitHub Desktop.
An animation with a kaleidoscope effect
import SwiftUI
struct HalfShape: Shape {
let left: Bool
func path(in rect: CGRect) -> Path {
return Path { path in
let width = rect.width
let height = rect.height
if left {
path.addRect(CGRect(x: 0, y: 0, width: width/2, height: height))
}
else {
path.addRect(CGRect(x: width/2, y: 0, width: width/2, height: height))
}
}
}
}
struct JumpingBallShape: Shape {
var value: CGFloat
let sizeF: CGFloat = 0.1
var animatableData: CGFloat {
get { return value }
set { value = newValue }
}
func path(in rect: CGRect) -> Path {
return Path { path in
let width = rect.width
let height = rect.height
let radiusX = sin(value*3)*width*0.4
let radiusY = sin(value*3)*height*0.4
let size = CGSize(width: width*sizeF*sin(value*2), height: height*sizeF*sin(value*2))
path.addEllipse(in: CGRect(origin: CGPoint(x: width/2 + cos(value)*radiusX - size.width, y: height/2 + sin(value)*radiusY - size.height), size: size))
}
}
}
struct AngleMirrorEffect: AnimatableModifier {
var value: Double
var animatableData: Double {
get { return value }
set { value = newValue }
}
func body(content: Content) -> some View {
ZStack {
content
.rotationEffect(Angle(radians: value))
.mask(HalfShape(left: true))
content
.rotationEffect(Angle(radians: value))
.scaleEffect(x: -1.0, y: 1.0, anchor: .center)
.mask(HalfShape(left: false))
}
.rotationEffect(Angle(radians: -value))
}
}
struct JumpingBallView: View {
@State var rot: CGFloat = 0.0
let count: Int
let offset: CGFloat
let line: CGFloat
let color: Color
var body: some View {
ZStack {
ForEach (0..<count) { index in
JumpingBallShape(value: rot + 0.1*CGFloat(index) + offset)
.stroke(color, lineWidth: line)
}
}
.blendMode(.plusLighter)
.onAppear{
withAnimation(Animation.linear(duration: 20.0).repeatForever(autoreverses: false)) {
self.rot = CGFloat.pi*2
}
}
}
}
struct KaleidoscopeView: View {
@State var rot: Double = 0.0
var body: some View {
VStack {
ZStack {
JumpingBallView(count: 6, offset: 0, line: 20.0, color: Color("darkRed"))
//.blur(radius: 33)
.hueRotation(Angle(degrees: -30))
JumpingBallView(count: 12, offset: CGFloat.pi*2/3, line: 4.0, color: Color("gold"))
.rotationEffect(Angle(degrees: 120))
JumpingBallView(count: 12, offset: CGFloat.pi*4/3, line: 1.0, color: Color("gold"))
.rotationEffect(Angle(degrees: 240))
}
.frame(width: 300, height: 300)
.modifier(AngleMirrorEffect(value: self.rot))
.modifier(AngleMirrorEffect(value: self.rot + Double.pi/3))
.modifier(AngleMirrorEffect(value: self.rot + Double.pi*2/3))
.onTapGesture {
withAnimation(Animation.linear(duration: 25.0).repeatForever(autoreverses: false)) {
self.rot = Double.pi*2
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment