Skip to content

Instantly share code, notes, and snippets.

@izakpavel
Created October 2, 2020 10:07
Show Gist options
  • Save izakpavel/e8dc69037304901beed93895fd4e7a68 to your computer and use it in GitHub Desktop.
Save izakpavel/e8dc69037304901beed93895fd4e7a68 to your computer and use it in GitHub Desktop.
A loading indicator in the style of this years Apple Event animation. Created for the first #SwiftUIWeeklyChallenge
//
// ContentView.swift
// SwiftUIWeeklyChallenge01
//
// Created by @myridiphis on 02/10/2020.
//
// not very tidy, but enjoy changing many of magical constants
import SwiftUI
func interpolateColor(_ i:Double) -> Color {
let colors = [UIColor(named: "c4"), UIColor(named: "c3"), UIColor(named: "c2"), UIColor(named: "c1")]
var interpolator: CGFloat = 0.0
var sIndex: Int = 0
if (i<0.33) {
interpolator = CGFloat(i)*3
}
else if (i<0.66) {
interpolator = (CGFloat(i)-0.333)*3
sIndex = 1
}
else {
interpolator = (CGFloat(i)-0.666)*3
sIndex = 2
}
var r1: CGFloat = 0.0
var g1: CGFloat = 0.0
var b1: CGFloat = 0.0
var r2: CGFloat = 0.0
var g2: CGFloat = 0.0
var b2: CGFloat = 0.0
var a: CGFloat = 0.0
colors[sIndex]?.getRed(&r1, green: &g1, blue: &b1, alpha: &a)
colors[sIndex+1]?.getRed(&r2, green: &g2, blue: &b2, alpha: &a)
let r = r2*interpolator + r1*(1.0-interpolator)
let g = g2*interpolator + g1*(1.0-interpolator)
let b = b2*interpolator + b1*(1.0-interpolator)
return Color(red: Double(r), green: Double(g), blue: Double(b))
}
struct LoadingView: View {
let circles = 100
let diameter: CGFloat = 100.0
let circleSize: CGFloat = 40.0
let cutOut: CGFloat = 0.8
@State var flipped: Bool = false
@State var startAngle: CGFloat = 0
func circlePosition(index: Int)-> CGPoint {
/*let baseAngle = CGFloat(index)/CGFloat(circles)*CGFloat.pi*2*cutOut
let angle:CGFloat = baseAngle + startAngle
let xCoord: CGFloat = diameter + (diameter-circleSize)*cos(angle)
let yCoord: CGFloat = flipped ? diameter + (diameter-circleSize)*sin(baseAngle) : diameter - (diameter-circleSize)*sin(baseAngle)
*/
let baseAngle = CGFloat(index)/CGFloat(circles)*CGFloat.pi*2*cutOut
let flipValue = 2*CGFloat.pi-baseAngle
let angle:CGFloat = flipped ? baseAngle + startAngle + flipValue : baseAngle + startAngle
let xCoord: CGFloat = diameter + (diameter-circleSize)*cos(angle)
let yCoord: CGFloat = diameter + (diameter-circleSize)*sin(angle)
return CGPoint(x: xCoord, y: yCoord)
}
func circleDelay(index: Int)-> Double {
//let angle:Double = Double(index)/Double(circles)*Double.pi*2*Double(cutOut)
return 5*Double(circles - index)/Double(circles)//(-cos(angle) + 1.0)*0.5
}
func animate() {
withAnimation {
self.flipped = !self.flipped
self.startAngle += CGFloat.pi/3
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
self.animate()
}
}
var body: some View {
ZStack {
ForEach (0 ..< circles) { index in
Circle()
.fill(interpolateColor(Double(index)/100.0))
.frame(width: circleSize, height: circleSize)
.position(self.circlePosition(index: index))
//.modifier(OnPathEffect(offsetValue: self.offset))
.animation(Animation.easeInOut(duration: 1.0).delay(self.circleDelay(index: index)))
}
}
.frame(width: 2*diameter, height: 2*diameter)
.onAppear() {
self.animate()
}
}
}
struct ContentView: View {
var body: some View {
ZStack {
VStack {
LoadingView()
Text("#SwiftUIWeeklyChallenge")
.font(Font.title.italic())
.foregroundColor(Color("c2"))
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.white)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment