Swift: 재생 속도를 변경할 수 있는 키프레임 애니메이션

12853 단어 MacOSXSwift

소개



RunCat의 키 프레임 애니메이션의 핵심 부분 구현에 대해 공개.
속도가 바뀌는 키 프레임 애니메이션 (소위 파라 파라 만화 또는 프레임 촬영 애니메이션)의 구현 방법에 대한 문헌이 없어 매우 어색했다.

데모




이 데모의 녀석은 보통 NSViewlayer 위에서 애니메이션하고 있기 때문에 간단하지만, 메뉴 바( NSStatusItem )상에서 재생하면 실제로는 더 정교한 것이 필요하게 된다.

출처


duration를 고정하고 부모 레이어의 speed를 조정한다는 것이 키모
나머지는 timeOffsetbeginTime의 역할 파악이 중요

AnimationLayer.swift
import Cocoa

class AnimationLayer: CALayer {

    //キーフレームアニメーションをするやつ
    private var keyFrameAnimation: CAKeyframeAnimation!

    //何かしらの初期設定(実装によってはいらない)
    public func initialize() {
        self.masksToBounds = true
        self.contentsScale = 2.0
    }

    //キーフレームアニメーションの用意
    public func setSequence(_ sequence: [NSImage]) {
        keyFrameAnimation = CAKeyframeAnimation(keyPath: "contents")
        keyFrameAnimation.calculationMode = .discrete //パラパラ漫画形式にするために必須な設定
        keyFrameAnimation.fillMode = .forwards
        keyFrameAnimation.repeatCount = Float.infinity
        keyFrameAnimation.autoreverses = false
        keyFrameAnimation.isRemovedOnCompletion = false
        keyFrameAnimation.beginTime = 0.0
        keyFrameAnimation.values = sequence
        keyFrameAnimation.duration = Double(sequence.count)
    }

    //アニメーション開始
    public func startAnimate() {
        if keyFrameAnimation == nil { return }
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        self.add(keyFrameAnimation, forKey: "running")
        CATransaction.commit()
    }

    //アニメーションのスピード変更
    public func updateSpeed(_ speed: Float) {
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        self.timeOffset = self.convertTime(CACurrentMediaTime(), from: nil)
        self.beginTime = CACurrentMediaTime()
        self.speed = speed
        CATransaction.commit()
    }

}

ViewController.swift
import Cocoa

class ViewController: NSViewController {

    let animationLayer = AnimationLayer()
    var timer: Timer? = nil

    override func viewDidLoad() {
        super.viewDidLoad()

        //アニメーションレイヤーを初期化して追加
        self.view.wantsLayer = true
        animationLayer.initialize()
        self.view.layer!.addSublayer(animationLayer)

        //アニメーションするためのコマ画像を用意する
        var icons = [NSImage]()
        for i in (1 ... 4) {
            let icon = NSImage(imageLiteralResourceName: "page" + String(i))
            icons.append(icon)
        }
        //フレームサイズと画像を設定してアニメーション開始
        animationLayer.frame = NSRect(x: 40, y: 40, width: self.view.bounds.width - 80, height: self.view.bounds.height - 80)
        animationLayer.setSequence(icons)
        animationLayer.startAnimate()

        //例として定期的にアニメーションをランダムなスピードに変更
        timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: true) { (t) in
            let speed = Float.random(in: 1 ... 5)
            self.animationLayer.updateSpeed(speed)
        }
    }

    override func viewWillDisappear() {
        timer?.invalidate()
    }

    override var representedObject: Any? {
        didSet {
        }
    }

}

비고



일단 이 방법을 베이스로 키프레임 애니메이션을 실시하는 것이 가능하지만, Core Animation는 마음대로 GPU를 사용할 수 있는 경우는 사용해 버릴 것 같고, 발열 문제를 유저로부터 지적되었다. GPU를 사용하지 않고 CPU의 소모가 작은 실장 방법을 알고 싶다.

좋은 웹페이지 즐겨찾기