Search code examples
iosanimationcareplicatorlayer

After CAReplicatorLayer animation in a `vc`'s `subview`, switch `vc` comes a strange issue


CAReplicator did not keep the state after the switch vc:

Dots of CAReplicator did not keep its scale after the vc switch back.

As you see, the circle animation is created by CAReplicator.

after the main vc switch to another vc, then switch back, the Circle's dots become very small. witch is set in the initial.

My code is below:

In the main vc:

 func initUI() {

    let lml_frame = CGRect.init(x: 0, y: 64, width: self.view.bounds.size.width, height: 400)
    lml_digtal_view = LMLDigitalDazzleAnimationView.init(frame: lml_frame)
    self.view.addSubview(lml_digtal_view!)
}

In the LMLDigitalDazzleAnimationView:

import Foundation
import UIKit

class LMLDigitalDazzleAnimationView: UIView {

    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
    // Drawing code
    }
    */

    var initFrame = CGRect.init(x: 0, y: 0, width: 320, height: 480)

    var fromColor = UIColor.init(red: 240/255.0, green: 77.0/255.0, blue: 48.0/255.0, alpha: 1.0).cgColor
    var toColor = UIColor.init(red: 220.0/255.0, green: 28.0/255.0, blue: 44.0/255.0, alpha: 1.0).cgColor

    var money:Float? = 1200.25 {

        didSet {
    
        
        }
    }

    override  init(frame: CGRect) {
        super.init(frame: frame)
        initFrame = frame
        initUI()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    func initUI(){
    
    
    let gradul_layer = CAGradientLayer.init()
    gradul_layer.frame = CGRect.init(x: 0, y: 0, width: initFrame.width, height: initFrame.height)
    gradul_layer.colors = [
        fromColor,
        toColor
    ]
    gradul_layer.startPoint = CGPoint.init(x: 0.5, y: 0.3)
    gradul_layer.endPoint = CGPoint.init(x: 0.5, y: 0.7)
    
    layer.addSublayer(gradul_layer)
    
    let wave_view0 = KHWaveView.init(frame: CGRect.init(x: 0, y: initFrame.height - 80, width: initFrame.width, height: 80))
    //wave_view.backgroundColor = UIColor.white
    wave_view0.waveColor = UIColor.init(red: 1, green: 1, blue: 1, alpha: 0.5)
    wave_view0.waveSpeed = 1.3
    wave_view0.waveTime = 0
    wave_view0.wave()
    self.addSubview(wave_view0)
    
    let wave_view = KHWaveView.init(frame: CGRect.init(x: 0, y: initFrame.height - 80, width: initFrame.width, height: 80))
    //wave_view.backgroundColor = UIColor.white
    wave_view.waveColor = UIColor.white
    wave_view.waveSpeed = 1.0
    wave_view.waveTime = 0
    wave_view.wave()
    
    
    self.addSubview(wave_view)
    
    animateCircle()
    
    animateDigitalIcrease(money: money!)
    
    
    
    }

    func animateCircle() -> Void {
    
        let r = CAReplicatorLayer()
        r.bounds = CGRect(x:0.0, y:0.0, width:260.0, height:260.0)
        r.cornerRadius = 10.0
        r.backgroundColor = UIColor.clear.cgColor
        r.position = CGPoint.init(x: self.bounds.width / 2.0, y: 160)
    
        self.layer.addSublayer(r)
    
        let dot = CALayer()
        dot.bounds = CGRect(x:0.0, y :0.0, width:6.0, height:6.0)
        dot.position = CGPoint(x:100.0, y:10.0)
        dot.backgroundColor = UIColor(white:1, alpha:1.0).cgColor
        dot.cornerRadius = 3.0
    
        r.addSublayer(dot)
    
        let nrDots: Int = 32
        r.instanceCount = nrDots
        let angle = CGFloat(2*M_PI) / CGFloat(nrDots)
        r.instanceTransform = CATransform3DMakeRotation(angle, 0.1, 0.1, 1.0)
    
        let duration:CFTimeInterval = 1.5
        let shrink = CABasicAnimation(keyPath: "transform.scale")
        shrink.fromValue = 1.0
        shrink.toValue = 1.0 // 0.5
        shrink.duration = duration
        shrink.repeatCount = Float.infinity
    
        dot.add(shrink, forKey: nil)
    
        r.instanceDelay = duration/Double(nrDots)
    
        dot.transform = CATransform3DMakeScale(0.1, 0.1, 0.1)
    
        delay(delay: duration) {
        
            let turn_key_path = "transform.rotation"
            let turn_ani = CABasicAnimation.init(keyPath: turn_key_path)
            turn_ani.isRemovedOnCompletion = false
            turn_ani.fillMode = kCAFillModeForwards
            turn_ani.toValue = M_PI*2
            turn_ani.duration = 2.0
            turn_ani.repeatCount = 2
            r.add(turn_ani, forKey: turn_key_path)
       
        }
    
    }

    func delay(delay:Double, closure:@escaping ()->()){
    
        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
    }

    func animateDigitalIcrease(money :Float){

        let frame = CGRect.init(x: 0, y: 0, width: 120, height: 80)
        let counterLabel = LMLDigitalIncreaseLabel.init(frame: frame, andDuration: 2.0, andFromValue: 0, andToValue: money)
        counterLabel?.center = CGPoint.init(x: self.bounds.size.width / 2.0, y: 130)
        self.addSubview(counterLabel!)
    
        counterLabel?.start()
     
        delay(delay: 5.0) {
            counterLabel?.stop()
            self.animateFadeShowSmallMoney()
        }
    
    }

    func animateFadeShowSmallMoney(){
  
        let border_view = UIView.init(frame: CGRect.init(x: 0, y: 0, width: 100, height: 30))
        border_view.layer.cornerRadius = 15
        border_view.layer.masksToBounds = true
        border_view.layer.borderWidth = 1
        border_view.backgroundColor = UIColor.clear
        border_view.layer.borderColor = UIColor.white.cgColor
    
    
        let small_money_frame = CGRect.init(x: 0, y: 0, width: 80, height: 30)
        let small_money = UILabel.init(frame: small_money_frame)
        small_money.center = border_view.center
        small_money.adjustsFontSizeToFitWidth = true
      
        small_money.textAlignment = NSTextAlignment.center
        small_money.text = "mo:" + String(format:"%.2f", money!)
        small_money.textColor = UIColor.white
        border_view.addSubview(small_money)
    
        border_view.alpha = 0.0
        self.addSubview(border_view)
        border_view.center = CGPoint.init(x: self.bounds.size.width/2.0, y: 220)
    
        UIView.animate(withDuration: 1.0) { 
            border_view.alpha = 1.0
        }
    
    }

}

My code is not good, you can advice me how to encapsulate a animation class better.


Solution

  • After many attention, I solve my issue:

        delay(delay: duration) {
    
            let turn_key_path = "transform.rotation"
            let turn_ani = CABasicAnimation.init(keyPath: turn_key_path)
            turn_ani.isRemovedOnCompletion = false
            turn_ani.fillMode = kCAFillModeForwards
            turn_ani.toValue = M_PI*2
            turn_ani.duration = 2.0
            turn_ani.repeatCount = 2
            r.add(turn_ani, forKey: turn_key_path)
            dot.transform = CATransform3DMakeScale(1, 1, 1) // add this line solve my issue.
        }