- Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
The final effect to be completed:
The first thing to do is draw a circle with the CAShapeLayer. Here you create a path by placing the center of the circle in the center of the view with a radius of 100, then setting the starting Angle and the ending Angle, which is shown by setting true. Then set the path of the shapeLayer to the path you just created, and finally add the shapeLayer to the Layer sublayer of the View.
let shapeLayer = CAShapeLayer()
let center = view.center
let circularPath = UIBezierPath(arcCenter: center, radius: 100, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
shapeLayer.path = circularPath.cgPath
view.layer.addSublayer(shapeLayer)
Copy the code
Next add a red circle around the shapeLayer.
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 10
Copy the code
The effect is as follows:
Next, add a click gesture to the view to animate the outer circle later.
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
Copy the code
Add a response method
@objc func handleTap() {
}
Copy the code
You need a shapeLayer to animate the outer circle, so put the shapeLayer outside and let the VC hold it. So in viewDidLoad I’m going to set shapeLayer’s strokeEnd to 0
shapeLayer.strokeEnd = 0
Copy the code
Then animate the shapeLayer in handleTap.
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
basicAnimation.toValue = 1
basicAnimation.duration = 2
shapeLayer.add(basicAnimation, forKey: "stokeAnimation")
Copy the code
So when you click on it, you draw a circle.
The problem is that the starting position should be above the circle instead of right, so you need to change the startAngle of circularPath so that the animation will start above the circle.
let circularPath = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: CGFloat.pi * 2, clockwise: true)
Copy the code
Another problem here is that the head of the circle is straight instead of circular, so you just need to change the shapeLayer lineCap.
shapeLayer.lineCap = .round
Copy the code
Now remove the black in the middle of the circle and change the shapeLayer fill color to colorless.
shapeLayer.fillColor = UIColor.clear.cgColor
Copy the code
Next, add a track layer to the progress bar.
let trackLayer = CAShapeLayer() trackLayer.path = circularPath.cgPath trackLayer.strokeColor = UIColor.lightGray.cgColor trackLayer.lineWidth = 10 trackLayer.fillColor = UIColor.clear.cgColor trackLayer.lineCap = .roundCopy the code
Now look like this:
Complete code:
import UIKit
class ViewController: UIViewController {
let shapeLayer = CAShapeLayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let center = view.center
let circularPath = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: CGFloat.pi * 2, clockwise: true)
let trackLayer = CAShapeLayer()
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = UIColor.lightGray.cgColor
trackLayer.lineWidth = 10
trackLayer.fillColor = UIColor.clear.cgColor
trackLayer.lineCap = .round
view.layer.addSublayer(trackLayer)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeEnd = 0
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 10
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = .round
view.layer.addSublayer(shapeLayer)
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
}
@objc func handleTap() {
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
basicAnimation.toValue = 1
basicAnimation.duration = 2
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
shapeLayer.add(basicAnimation, forKey: "stokeAnimation")
}
}
Copy the code