I am trying to create a circular progress view that has stroke outside. But my stroke starts from inside of the view instead of the start from the outside it like border. How can I solve it?
My code:
var progressLayer = CAShapeLayer()
var trackLayer = CAShapeLayer()
var progressLineWidth: CGFloat = 20
var progressColor = UIColor.green
var progress: Float = 0.5
let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0 - 2, y: frame.size.height / 2.0 - 2), radius: (frame.size.width) / 2, startAngle: -(.pi / 2), endAngle: .pi * 1.5, clockwise: true)
trackLayer.path = circlePath.cgPath
trackLayer.strokeColor = UIColor.gray.cgColor
trackLayer.lineWidth = 10
trackLayer.strokeEnd = 1.0
trackLayer.lineDashPattern = [4,4]
trackLayer.fillColor = UIColor.red.cgColor
layer.addSublayer(trackLayer)
progressLayer.path = circlePath.cgPath
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.strokeColor = progressColor.cgColor
progressLayer.lineWidth = progressLineWidth
progressLayer.strokeEnd = CGFloat(progress)
progressLayer.strokeStart = 0
progressLayer.lineDashPattern = [4,4]
layer.addSublayer(progressLayer)
Result:
What I want to achive:
Gray and green strokes should start from the outside of the red circle.
You can subtract the middle circle by a simple mask like:
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(rect: self.bounds).cgPath.subtracting(circlePath.cgPath)
layer.mask = maskLayer
class CircularProgressBarView: UIView {
var progress: CGFloat = 0 { didSet { layoutSubviews() } }
var progressLineWidth: CGFloat = 20 { didSet { layoutSubviews() } }
var progressColor = UIColor.green { didSet { layoutSubviews() } }
var pattern: [NSNumber] = [4,4] { didSet { layoutSubviews() } }
private var customLayer = CALayer()
override func layoutSubviews() {
super.layoutSubviews()
customLayer.removeFromSuperlayer()
customLayer = CALayer()
let bounds = CGRect(
x: progressLineWidth,
y: progressLineWidth,
width: bounds.width - progressLineWidth*2,
height: bounds.height - progressLineWidth*2
)
let circlePath = UIBezierPath(ovalIn: bounds)
let trackLayer = CAShapeLayer()
trackLayer.path = circlePath.cgPath
trackLayer.strokeColor = UIColor.gray.cgColor
trackLayer.lineWidth = progressLineWidth
trackLayer.lineDashPattern = pattern
trackLayer.fillColor = UIColor.red.cgColor
customLayer.addSublayer(trackLayer)
let progressLayer = CAShapeLayer()
progressLayer.path = circlePath.cgPath
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.strokeColor = progressColor.cgColor
progressLayer.lineWidth = progressLineWidth * 2
progressLayer.strokeEnd = progress
progressLayer.lineDashPattern = pattern
customLayer.addSublayer(progressLayer)
let containerPath = UIBezierPath(rect: self.bounds)
containerPath.append(circlePath.reversing())
let maskLayer = CAShapeLayer()
maskLayer.path = containerPath.cgPath
customLayer.mask = maskLayer
layer.addSublayer(customLayer)
}
}
Of course you can rotate the whole layer (or view) to make it start from 12 O'clock