Skip to content

Instantly share code, notes, and snippets.

@RustyKnight
Created August 2, 2018 23:38
Show Gist options
  • Save RustyKnight/9663a0b3a5f3c93d7a117ca4b86a658f to your computer and use it in GitHub Desktop.
Save RustyKnight/9663a0b3a5f3c93d7a117ca4b86a658f to your computer and use it in GitHub Desktop.
A implementation of a circular progress image based on a UIImageView
import Foundation
import UIKit
public class ImageViewProgess: UIImageView {
fileprivate var actualImage: UIImage?
fileprivate var grayScaleImage: UIImage?
@IBInspectable public override var image: UIImage? {
didSet {
actualImage = image
if imageLayer != nil {
imageLayer.contents = actualImage?.cgImage
}
grayScaleImage = actualImage?.noir?.with(alpha: actualGrayScaleAlpha)
super.image = grayScaleImage
}
}
fileprivate var actualGrayScaleAlpha: Double = 1.0 {
didSet {
grayScaleImage = actualImage?.noir?.with(alpha: actualGrayScaleAlpha)
setNeedsLayout()
setNeedsDisplay()
}
}
@IBInspectable var greyScaleAlpha: Double {
set {
actualGrayScaleAlpha = Swift.min(1.0, Swift.max(newValue, 0.0))
setNeedsLayout()
setNeedsDisplay()
}
get {
return actualGrayScaleAlpha
}
}
@IBInspectable var startAngle: Double = -90.0 {
didSet {
guard shapeLayer != nil else {
return
}
shapeLayer.path = path(at: progress).cgPath
setNeedsLayout()
setNeedsDisplay()
}
}
@IBInspectable var progress: Double = 0.0 {
didSet {
guard shapeLayer != nil else {
return
}
shapeLayer.path = path(at: progress).cgPath
setNeedsLayout()
setNeedsDisplay()
}
}
internal var shapeLayer: CAShapeLayer!
internal var imageLayer: CALayer!
public override func awakeFromNib() {
super.awakeFromNib()
commonInit()
}
internal func commonInit() {
actualImage = image
grayScaleImage = actualImage?.noir?.with(alpha: actualGrayScaleAlpha)
image = actualImage
shapeLayer = CAShapeLayer()
shapeLayer.frame = bounds
shapeLayer.contentsGravity = .center
shapeLayer.path = path(at: progress).cgPath
shapeLayer.fillColor = UIColor.red.cgColor
imageLayer = CALayer()
imageLayer.frame = bounds
imageLayer.contentsGravity = .center
imageLayer.contents = actualImage?.cgImage
imageLayer.mask = shapeLayer
layer.addSublayer(imageLayer)
}
public override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
commonInit()
startAngle = -90.0
greyScaleAlpha = 1.0
}
public override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.frame = bounds
imageLayer.frame = bounds
}
internal func path(at progress: Double) -> UIBezierPath {
let size = bounds.size
let center = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
// Want to "over fill" the image area, so the mask can be applied
// to the entire image
let radius = Swift.max(size.width, size.height)
let startAngle = -90.0
let clockwise = true;
let path = UIBezierPath(arcCenter: center,
radius: CGFloat(radius),
startAngle: CGFloat(startAngle.degreesToRadians),
endAngle: CGFloat((startAngle + (360.0 * progress)).degreesToRadians),
clockwise: clockwise)
path.addLine(to: center)
path.close()
return path
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment