Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save joshuajhomann/4c6964a048c966254938978afef57964 to your computer and use it in GitHub Desktop.
Save joshuajhomann/4c6964a048c966254938978afef57964 to your computer and use it in GitHub Desktop.
static member lookup progress
import UIKit
import PlaygroundSupport
protocol ProgressRenderer {
var draw: (Double, CGRect) -> Void { get }
}
struct ConcreteProgressRenderer: ProgressRenderer {
let draw: (Double, CGRect) -> Void
}
extension ProgressRenderer where Self == ConcreteProgressRenderer {
static func arc(color: UIColor) -> ConcreteProgressRenderer {
.init { proportion, rect in
let radius: Double = min(rect.width, rect.height) / 2
let center = CGPoint(x: rect.midX, y: rect.midX)
let path = UIBezierPath()
color.setFill()
path.move(to: center)
path.addLine(to: .init(x: 0, y: radius))
path.addArc(withCenter: center, radius: radius, startAngle: 0, endAngle: proportion * 2 * .pi, clockwise: true)
path.close()
path.fill()
}
}
static func ring(width: Double, color: UIColor) -> ConcreteProgressRenderer {
.init { proportion, rect in
color.setStroke()
let center = CGPoint(x: rect.midX, y: rect.midX)
let radius: Double = (min(rect.width, rect.height) - width) / 2
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: proportion * 2 * .pi, clockwise: true)
path.lineWidth = width
path.lineCapStyle = .round
path.stroke()
}
}
}
final class ProgressView: UIView {
var proportion = 0.0 {
didSet {
setNeedsDisplay()
}
}
private let renderer: ProgressRenderer
init(_ renderer: ProgressRenderer) {
self.renderer = renderer
super.init(frame: .zero)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
renderer.draw(proportion, rect)
}
}
let progressView = ProgressView(.arc(color: .blue))
progressView.frame = .init(origin: .zero, size: .init(width: 200, height: 200))
progressView.transform = .init(rotationAngle: -.pi / 2)
PlaygroundPage.current.liveView = progressView
let progressSubscription = Timer
.publish(every: 0.05, on: .main, in: .common)
.autoconnect()
.map { _ in 0.01 }
.scan(0.0, +)
.sink(receiveValue: { progressView.proportion = $0 })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment