Okay so here's how it goes.
The gray area is a UIView, and masked it with CAShapeLayer
. I appended two UIBezierPath
and used the Even Odd Rule
to remove a portion of that gray area. That is why it shows a line as if it's demonstrating a semi-circle on the left.
The red background is just container view.
Now my problem is that when I animate my UIView
, it's as if the mask isn't updating correctly with animating UIView
.
Here's the UIView
animation part:
func didCompleteItem() {
self.bar.plainProgressBarLeftAnchor?.constant = self.bar.bounds.width * (self.completedItemCount*self.barMeterMultiplier) / self.bar.bounds.width - self.bar.meterCornerRadius
UIView.animate(withDuration: 1.0, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
self.bar.layoutIfNeeded()
}, completion: nil)
}
Now, here's the layoutSubviews
part of it, if you need to see how the CAShapeLayer
was created.
override func layoutSubviews() {
super.layoutSubviews()
backgroundColor = GradientColor(.leftToRight, frame: self.bounds, colors: GradientFlatRed())
layer.masksToBounds = true
layer.cornerRadius = meterCornerRadius
createMask()
}
var shapeLayer: CAShapeLayer = CAShapeLayer()
func createMask() {
let bPath = UIBezierPath(roundedRect: plainProgressBar.bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width: 0, height: 0))
let semiCircle = UIBezierPath(arcCenter: CGPoint(x: bounds.origin.x, y: plainProgressBar.bounds.origin.y+meterCornerRadius), radius: meterCornerRadius, startAngle: 3 * CGFloat.pi / 2, endAngle: CGFloat.pi / 2, clockwise: true)
shapeLayer.frame = layer.bounds
bPath.append(semiCircle)
shapeLayer.path = bPath.cgPath
shapeLayer.fillRule = kCAFillRuleEvenOdd
plainProgressBar.layer.mask = shapeLayer
}
Drawing a stretchable circle and changing the width of the image view that portrays the circle would give you the effect you're after, pretty much without effort and with none of the artifacts you're experiencing: