创建雨码矩阵效果

Creating raining code Matrix effect

创建了一个 CATextLayer 的子 class,我在其中附加了淡入动画,然后将其添加到附加了 dropThru 动画的 CATextLayer。尝试创建矩阵电影下雨代码效果的目标。工作得相当好,但事实上它缓慢但肯定会把自己推入地下,我怀疑是因为我不断添加越来越多的层。如何检测图层何时离开屏幕以便我可以将其删除。

这是代码...

class CATextSubLayer: CATextLayer, CAAnimationDelegate {

    private var starter:Float!
    private var ender:Float!

   required override init(layer: Any) {
    super.init(layer: layer)
    //UIFont.availableFonts()
    self.string = randomString(length: 1)
    self.backgroundColor = UIColor.black.cgColor
    self.foregroundColor = UIColor.white.cgColor
    self.alignmentMode = kCAAlignmentCenter
    self.font = CTFontCreateWithName("AvenirNextCondensed-BoldItalic" as CFString?, fontSize, nil)
    self.fontSize = 16
    self.opacity = 0.0
    makeFade()
}

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

}

func randomString(length: Int) -> String {

    let letters : NSString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let len = UInt32(letters.length)

    var randomString = ""
    for _ in 0 ..< length {
        let rand = arc4random_uniform(len)
        var nextChar = letters.character(at: Int(rand))
        randomString += NSString(characters: &nextChar, length: 1) as String
    }

    return randomString
}

func makeFade() {
        let rands = Double(arc4random_uniform(UInt32(4)))
        let fadeInAndOut = CABasicAnimation(keyPath: "opacity")
        fadeInAndOut.duration = 16.0;
        fadeInAndOut.repeatCount = 1
        fadeInAndOut.fromValue = 0.0
        fadeInAndOut.toValue = 1
        fadeInAndOut.isRemovedOnCompletion = true
        fadeInAndOut.fillMode = kCAFillModeForwards;
        fadeInAndOut.delegate = self
        fadeInAndOut.beginTime = CACurrentMediaTime() + rands
        self.add(fadeInAndOut, forKey: "opacity")

}

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    self.removeAllAnimations()
}
}

与外部 loop/View 控制器..

class ViewController: UIViewController, CAAnimationDelegate {

var beeb: CATextSubLayer!
var meeb: CATextLayer!
var lines = [Int]()

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.black
        // Do any additional setup after loading the view, typically from a nib.
    meeb = CATextLayer()
    for bing in stride(from:0, to: Int(view.bounds.width), by: 16) {
        lines.append(bing)
    }
    for _ in 0 ..< 9 {
        Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(makeBeeb), userInfo: nil, repeats: true)
    }
}

func makeBeeb() {
    let rands = Double(arc4random_uniform(UInt32(4)))
    let beeb = CATextSubLayer(layer: meeb)
    let randx = Int(arc4random_uniform(UInt32(lines.count)))
    let monkey = lines[randx]
    beeb.frame = CGRect(x: monkey, y: 0, width: 16, height: 16)
    let dropThru = CABasicAnimation(keyPath: "position.y")
    dropThru.duration = 12.0;
    dropThru.repeatCount = 1
    dropThru.fromValue = 1
    dropThru.toValue = view.bounds.maxY
    dropThru.isRemovedOnCompletion = true
    dropThru.fillMode = kCAFillModeForwards;
    dropThru.beginTime = CACurrentMediaTime() + rands
    dropThru.delegate = self
    beeb.add(dropThru, forKey: "position.y")
    self.view.layer.addSublayer(beeb)
}

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    self.view.layer.removeAllAnimations()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

How can I detect when an layer had left the screen so I may delete it

您已经为 CABasicAnimation 提供了一个委托,它会在动画结束时调用。那是你移除图层的信号。 (您正在删除动画而不是图层本身。)

据我了解您的代码,您可以在位置动画结束时删除图层。此时它应该已经离开了父视图的边界。

顺便说一句。删除和添加层会降低性能。相反,您应该将图层重新用于下一个动画。