Build a custom circular progress bar in UIKit
Vector drawing with CAShapeLayer plus strokeEnd animation.
Draw an arc with UIBezierPath, assign it to a CAShapeLayer path, set lineWidth and no fill, animate strokeEnd 0 to 1.
WHAT THIS TESTS This evaluates whether you reach for Core Animation shape layers, which are GPU-friendly and resolution independent, rather than manual Core Graphics redrawing, and whether you know how strokeEnd creates the progress effect.
A GOOD ANSWER COVERS Build the ring geometry with UIBezierPath, using the arcCenter, radius, startAngle, and endAngle initializer to describe a full circle, conventionally starting at the top, which is minus pi over two. Create a CAShapeLayer, assign that path to its path property, set strokeColor for the progress color, set fillColor to clear so the interior is not filled, and set lineWidth for thickness. The layer's strokeEnd property, ranging from 0 to 1, controls how much of the stroke is drawn, so it maps directly to progress. Add the layer as a sublayer of the view. Often you add a second track CAShapeLayer behind it with a faint color and strokeEnd of 1.
COMMON WRONG ANSWERS Subclassing UIView and redrawing the arc in draw(_:) on every progress change, which is slow and not animatable smoothly. Forgetting to set fillColor to clear, producing a filled disc. Animating frame or path instead of strokeEnd. Setting lineCap incorrectly so the ends look blocky.
LIKELY FOLLOW-UPS How to animate the change: create a CABasicAnimation on keyPath strokeEnd from the old to the new value with a duration, add it to the layer, and set the model value so it persists. Why you must update the path on layoutSubviews when the view resizes. Adding lineCap = .round for nicer ends and a gradient via masking.
ONE CONCRETE EXAMPLE In layoutSubviews you compute a UIBezierPath circle centered in bounds with radius based on the smaller dimension. progressLayer.path uses it, progressLayer.fillColor = UIColor.clear.cgColor, progressLayer.strokeColor = tint, progressLayer.lineWidth = 8, progressLayer.lineCap = .round. To show 70 percent you create a CABasicAnimation(keyPath: "strokeEnd") from 0 to 0.7 over 0.3 seconds, add it, then set progressLayer.strokeEnd = 0.7 so the ring animates filling to seventy percent and stays there.
Read the original → developer.apple.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.