on calling startAnimation() the stroke Animation is not showing up, however, on using UIView.animate inside startAnimation function, it is working fine, only CABasicAnimation is not working. I am not sure what's wrong with this code. The frame is also coming fine, just the animation not showing up.
class ToastView: UIView {
lazy var label: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 14, weight: .regular)
return label
}()
lazy var subLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.fillColor = nil
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.lineCap = .round
shapeLayer.lineWidth = 2
return shapeLayer
}()
override init(frame: CGRect) {
super.init(frame: frame)
customInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
customInit()
}
private func customInit() {
backgroundColor = .black
self.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
let constraints = [
label.topAnchor.constraint(equalTo: self.topAnchor, constant: 2),
label.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 3),
label.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 4),
label.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 4)
]
NSLayoutConstraint.activate(constraints)
layer.borderWidth = 1
layer.borderColor = UIColor.white.cgColor
layer.cornerRadius = 4
layer.masksToBounds = true
}
func startAnimation(toastMessage: String) {
self.label.text = toastMessage
self.layer.insertSublayer(subLayer, at: 0)
subLayer.frame = layer.frame
subLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: 4).cgPath
subLayer.masksToBounds = true
let strokeAnimation = CABasicAnimation(keyPath: "strokeEnd")
strokeAnimation.beginTime = 0
strokeAnimation.fromValue = 0
strokeAnimation.toValue = 1
strokeAnimation.duration = 1.5
strokeAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
subLayer.add(strokeAnimation, forKey: "")
//animate coming up with message
}
}
Based on your comments, you are adding your ToastView
in Storyboard, with fixed dimensions.
So, let's assume it's size is 200 x 40
, centered horizontally, 12-points from the top (of the safe area), so it looks like this:
If we call your startAnimation(...)
func, it ends up looking like this:
So, the first issue is that you are setting the sublayer frame like this:
subLayer.frame = layer.frame
which offsets the bezier path. It should be:
subLayer.frame = self.bounds
Now it looks like this:
If we zoom in, we can see a faint "green":
but that's not what you want. You've set layer.masksToBounds = true
, so it ends up clipping the sublayer.
If we set layer.masksToBounds = false
, we get this:
and zoomed in:
Still, only slightly more green showing.
So, let's also change to subLayer.masksToBounds = true
to subLayer.masksToBounds = false
:
and we see the strokeEnd
animation just fine.
You didn't clarify what you're really going for... if this looks right, you should be on your way.
Note: A view's layer border will be drawn on top of any sublayers / subviews. So if you want the Green outline to cover the White outline, you'll need to take a few more steps.