Skip to content

Instantly share code, notes, and snippets.

@chriseidhof
Created June 12, 2019 13:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chriseidhof/90dbc3aa780e25a025122d9978a4aa24 to your computer and use it in GitHub Desktop.
Save chriseidhof/90dbc3aa780e25a025122d9978a4aa24 to your computer and use it in GitHub Desktop.
//
// ContentView.swift
// ActivityIndicator
//
// Created by Chris Eidhof on 11.06.19.
// Copyright © 2019 Chris Eidhof. All rights reserved.
//
import SwiftUI
import Combine
final class TimedCounter: BindableObject {
var counter: Int = 0 {
didSet {
didChange.send(counter)
}
}
let didChange = PassthroughSubject<Int, Never>()
var timer: Timer! = nil
init(interval: TimeInterval) {
timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true, block: { _ in
self.counter += 1
})
}
deinit {
timer?.invalidate()
}
}
struct RelativePosition: ViewModifier {
let x, y: CGFloat
init(x: CGFloat, y: CGFloat) {
self.x = x
self.y = y
}
func body(content: Content) -> some View {
GeometryReader { proxy in
content.position(x: self.x * proxy.size.width, y: self.y * proxy.size.height)
}
}
}
extension View {
func relativePosition(x: CGFloat, y: CGFloat) -> some View {
return Modified(content: self, modifier: RelativePosition(x: x, y: y))
}
}
struct ActivityIndicator: View {
@ObjectBinding var timer: TimedCounter
let speed: TimeInterval
init(speed: TimeInterval = 2) {
timer = TimedCounter(interval: speed)
self.speed = speed
}
var body: ActivityIndicatorContent {
return ActivityIndicatorContent(count: $timer.counter, speed: speed)
}
}
struct ActivityIndicatorContent: View {
@Binding var count: Int
let numberOfSegments: Int
let speed: TimeInterval
init(count: Binding<Int>, numberOfSegments: Int = 10, speed: TimeInterval) {
self.numberOfSegments = numberOfSegments
self.$count = count
self.speed = speed
}
let relativeHeight: CGFloat = 0.25
var y: CGFloat {
return relativeHeight - (CGFloat(numberOfSegments)/80)
}
let from: Color = .black
var body: some View {
ZStack {
ForEach(0..<self.numberOfSegments) { num in
Capsule()
.fill(self.from)
.brightness(Double(num)/Double(self.numberOfSegments))
.relativeSize(width: 0.1, height: self.relativeHeight)
.relativePosition(x: 0.5, y: self.y)
.rotationEffect(.degrees(Double(num) * (360/Double(self.numberOfSegments))), anchor: .center)
}
}.drawingGroup()
.rotationEffect(Angle.degrees(Double(count) * 360))
.animation(Animation.basic(duration: speed))
}
}
struct ContentView : View {
var body: some View {
VStack {
ActivityIndicator()
.frame(width: 50, height: 50)
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
Group {
ForEach(1..<10) { _ in
ActivityIndicator()
.frame(width: 50, height: 50)
}
}
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment