Home > Net >  Swift pulse animation non circle
Swift pulse animation non circle

Time:10-16

I'm trying to create pulse animation rectangular shape I have code:

func createPulse() {
    for _ in 0...3 {
        let circularPath = UIBezierPath(arcCenter: .zero, radius: view.bounds.size.height/2, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
        let pulseLayer = CAShapeLayer()
        pulseLayer.path = circularPath.cgPath
        pulseLayer.lineWidth = 2
        pulseLayer.fillColor = UIColor.clear.cgColor
        
        pulseLayer.lineCap = CAShapeLayerLineCap.round
        pulseLayer.position = CGPoint(x: binauralBackView.frame.size.width/2, y: binauralBackView.frame.size.height/2)
        pulseLayer.cornerRadius = binauralBackView.frame.width/2
        binauralBackView.layer.insertSublayer(pulseLayer, at: 0)
        pulseLayers.append(pulseLayer)
    }
    DispatchQueue.main.asyncAfter(deadline: .now()   0.1) {
        self.animatePulse(index: 0)
        DispatchQueue.main.asyncAfter(deadline: .now()   0.3) {
            self.animatePulse(index: 1)
            DispatchQueue.main.asyncAfter(deadline: .now()   0.5) {
                self.animatePulse(index: 2)
            }
        }
    }
}

func animatePulse(index: Int) {
    pulseLayers[index].strokeColor = #colorLiteral(red: 0.7215686275, green: 0.5137254902, blue: 0.7647058824, alpha: 1).cgColor
    let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
    scaleAnimation.duration = 2
    scaleAnimation.fromValue = 0.0
    scaleAnimation.toValue = 0.9
    scaleAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
    scaleAnimation.repeatCount = .greatestFiniteMagnitude
    pulseLayers[index].add(scaleAnimation, forKey: "scale")
    
    let opacityAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
    opacityAnimation.duration = 2
    opacityAnimation.fromValue = 0.9
    opacityAnimation.toValue = 0.0
    opacityAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
    opacityAnimation.repeatCount = .greatestFiniteMagnitude
    pulseLayers[index].add(opacityAnimation, forKey: "opacity")
}

and have result

enter image description here

Note: You can add CABasicAnimation for opacity too in animationGroup if this solution works for you.

extension UIView {
    /// animate the border width
    func animateBorderWidth(toValue: CGFloat, duration: Double) -> CABasicAnimation {
        let widthAnimation = CABasicAnimation(keyPath: "borderWidth")
        widthAnimation.fromValue = layer.borderWidth
        widthAnimation.toValue = toValue
        widthAnimation.duration = duration
        return widthAnimation
    }
    
    /// animate the scale
    func animateScale(toValue: CGFloat, duration: Double) -> CABasicAnimation {
        let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
        scaleAnimation.fromValue = 1.0
        scaleAnimation.toValue = toValue
        scaleAnimation.duration = duration
        scaleAnimation.repeatCount = .infinity
        scaleAnimation.isRemovedOnCompletion = false
        scaleAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
        return scaleAnimation
    }
    
    func pulsate(animationDuration: CGFloat) {
        
        var animationGroup = CAAnimationGroup()
        animationGroup = CAAnimationGroup()
        animationGroup.duration = animationDuration
        animationGroup.repeatCount = Float.infinity
        
        let newLayer = CALayer()
        newLayer.bounds = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
        newLayer.cornerRadius = self.frame.width/2
        newLayer.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
        newLayer.cornerRadius = self.frame.width/2
        
        animationGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.default)
        
        animationGroup.animations = [animateScale(toValue: 6.0, duration: 2.0),
                                     animateBorderWidth(toValue: 1.2, duration: animationDuration)]
        newLayer.add(animationGroup, forKey: "pulse")
        self.layer.cornerRadius = self.frame.width/2
        self.layer.insertSublayer(newLayer, at: 0)
    }
}

Usage:

class ViewController: UIViewController {
    @IBOutlet weak var pulseView: UIView!
    override func viewDidLoad() {
        super.viewDidLoad()
        pulseView.pulsate(animationDuration: 1.0)
    }
}
  • Related