The following codes used to work in swift 2 but in swift 3 it loads the image with effect but it puts a gray square on top of image on the second touch!!!
I use sdWebImage to show the progress indicator
call like this:
AttractionImage.sd_setImage(with: url, placeholderImage: nil, options: .progressiveDownload , progress: {(receivedSize, expectedSize) → Void in
progressIndicatorView.progress = CGFloat(receivedSize)/CGFloat(expectedSize)
}) { (image, error, _, _) → Void in
progressIndicatorView.reveal()
}
here is the original article:
https://www.raywenderlich.com/94302/implement-circular-image-loader-animation-cashapelayer
import UIKit
class CircularLoaderView: UIView {
let circlePathLayer = CAShapeLayer()
let circleRadius: CGFloat = 20.0
var progress: CGFloat {
get {
return circlePathLayer.strokeEnd
}
set {
//print("New value \(newValue)")
if (newValue > 1) {
circlePathLayer.strokeEnd = 1
} else if (newValue < 0) {
circlePathLayer.strokeEnd = 0
} else {
circlePathLayer.strokeEnd = newValue
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
func configure() {
circlePathLayer.frame = bounds
circlePathLayer.lineWidth = 2
circlePathLayer.fillColor = UIColor.clear.cgColor
circlePathLayer.strokeColor = UIColor.black.cgColor
// layer.addSublayer(circlePathLayer)
//backgroundColor = UIColor.white
progress = 0
}
func circleFrame() -> CGRect {
var circleFrame = CGRect(x: 0, y: 0, width: 2*circleRadius, height: 2*circleRadius)
circleFrame.origin.x = circlePathLayer.bounds.midX - circleFrame.midX
circleFrame.origin.y = circlePathLayer.bounds.midY - circleFrame.midY
return circleFrame
}
func circlePath() -> UIBezierPath {
return UIBezierPath(ovalIn: circleFrame())
}
override func layoutSubviews() {
super.layoutSubviews()
circlePathLayer.frame = bounds
circlePathLayer.path = circlePath().cgPath
}
func reveal() {
backgroundColor = UIColor.clear
progress = 1
circlePathLayer.removeAnimation(forKey: "strokeEnd")
circlePathLayer.removeFromSuperlayer()
superview?.layer.mask = circlePathLayer
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let finalRadius = sqrt((center.x*center.x) + (center.y*center.y))
let radiusInset = finalRadius - circleRadius
let outerRect = circleFrame().insetBy(dx: -radiusInset, dy: -radiusInset)
let toPath = UIBezierPath(ovalIn: outerRect).cgPath
//2
let fromPath = circlePathLayer.path
let fromLineWidth = circlePathLayer.lineWidth
//3
CATransaction.begin()
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
circlePathLayer.lineWidth = 2*finalRadius
circlePathLayer.path = toPath
CATransaction.commit()
//4
let lineWidthAnimation = CABasicAnimation(keyPath: "lineWidth")
lineWidthAnimation.fromValue = fromLineWidth
lineWidthAnimation.toValue = 2*finalRadius
let pathAnimation = CABasicAnimation(keyPath: "path")
pathAnimation.fromValue = fromPath
pathAnimation.toValue = toPath
//5
let groupAnimation = CAAnimationGroup()
groupAnimation.duration = 1
groupAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
groupAnimation.animations = [pathAnimation, lineWidthAnimation]
// groupAnimation.delegate = self
circlePathLayer.add(groupAnimation, forKey: "strokeWidth")
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
superview?.layer.mask = nil
}
}