Reputation: 25
I want to add an animation in my progress bar which is UIView based. Here is my code.
@IBDesignable class PlainHorizontalProgressBar: UIView {
@IBInspectable var color: UIColor = .green {
didSet { setNeedsDisplay() }
}
var progress: CGFloat = 0 {
didSet { setNeedsDisplay() }
}
private let progressLayer = CALayer()
private let backgroundMask = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
setupLayers()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupLayers()
}
private func setupLayers() {
layer.addSublayer(progressLayer)
}
override func draw(_ rect: CGRect) {
backgroundColor = .grey
backgroundColor?.setFill()
UIBezierPath(roundedRect: rect, cornerRadius: rect.height * 0.25).fill()
backgroundMask.path = UIBezierPath(roundedRect: rect, cornerRadius: rect.height * 0.25).cgPath
layer.mask = backgroundMask
let progressRect = CGRect(origin: .zero, size: CGSize(width: rect.width * progress, height: rect.height))
progressLayer.frame = progressRect
layer.addSublayer(progressLayer)
progressLayer.backgroundColor = color.cgColor
}
}
The scenario here is, I have ViewController A and ViewController B, This progress bar I have on ViewController B, I am assigning a value from ViewController A to ViewController B (example: myView.progress = 0.5 ) now when i am coming to ViewController B my progress bar is already filled half but what I want is, when I will come to ViewController B this should animate and filled front of me when I land on viewController B.
Upvotes: 0
Views: 1486
Reputation: 535138
The main problem here is that your draw
implementation is wrong. Or, to put it better, your draw
implementation should not exist at all. The only thing that should happen in draw
is drawing.
If you're going to add sublayers, you need a specific method that is called just once that adds the sublayers.
If you're going to change the frame of one of those sublayers, you need another specific method that changes the frame of the (already existing) sublayer. As soon as you separate that, it will be a lot more obvious how to animate the change in frame. In fact, because this is a layer, the animation will happen automatically.
class PlainHorizontalProgressBar: UIView {
var color: UIColor = .green {
didSet { update() }
}
var progress: CGFloat = 0 {
didSet { update() }
}
private let progressLayer = CALayer()
private let backgroundMask = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
setupLayers()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupLayers()
}
private func setupLayers() {
layer.addSublayer(progressLayer)
}
override func layoutSubviews() {
super.layoutSubviews()
backgroundMask.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.bounds.size.height * 0.25).cgPath
layer.mask = backgroundMask
update()
}
func update() {
let progressRect = CGRect(origin: .zero, size: CGSize(width: self.bounds.size.width * progress, height: self.bounds.size.height))
progressLayer.frame = progressRect
progressLayer.backgroundColor = color.cgColor
}
}
The part about being allowed to set progress
values between 1 and 100 is a matter of elementary arithmetic and is left as an exercise for the reader.
Upvotes: 1