Swift: 재생 속도를 변경할 수 있는 키프레임 애니메이션
소개
 RunCat의 키 프레임 애니메이션의 핵심 부분 구현에 대해 공개.
속도가 바뀌는 키 프레임 애니메이션 (소위 파라 파라 만화 또는 프레임 촬영 애니메이션)의 구현 방법에 대한 문헌이 없어 매우 어색했다.
 데모
 
이 데모의 녀석은 보통 NSView 의 layer 위에서 애니메이션하고 있기 때문에 간단하지만, 메뉴 바( NSStatusItem )상에서 재생하면 실제로는 더 정교한 것이 필요하게 된다.
 출처
duration를 고정하고 부모 레이어의 speed를 조정한다는 것이 키모
나머지는 timeOffset와 beginTime의 역할 파악이 중요
AnimationLayer.swiftimport 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.swiftimport 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의 소모가 작은 실장 방법을 알고 싶다.
                
                    
        
    
    
    
    
    
                
                
                
                
                    
                        
                            
                            
                            Reference
                            
                            이 문제에 관하여(Swift: 재생 속도를 변경할 수 있는 키프레임 애니메이션), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
                                
                                https://qiita.com/Kyome/items/15eb1893c48a64900e12
                            
                            
                            
                                텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                            
                            
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                            
                            
                        
                    
                
                
                
            

이 데모의 녀석은 보통
NSView 의 layer 위에서 애니메이션하고 있기 때문에 간단하지만, 메뉴 바( NSStatusItem )상에서 재생하면 실제로는 더 정교한 것이 필요하게 된다.출처
duration를 고정하고 부모 레이어의 speed를 조정한다는 것이 키모
나머지는 timeOffset와 beginTime의 역할 파악이 중요
AnimationLayer.swiftimport 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.swiftimport 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의 소모가 작은 실장 방법을 알고 싶다.
                
                    
        
    
    
    
    
    
                
                
                
                
                    
                        
                            
                            
                            Reference
                            
                            이 문제에 관하여(Swift: 재생 속도를 변경할 수 있는 키프레임 애니메이션), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
                                
                                https://qiita.com/Kyome/items/15eb1893c48a64900e12
                            
                            
                            
                                텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                            
                            
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                            
                            
                        
                    
                
                
                
            
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()
    }
}
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의 소모가 작은 실장 방법을 알고 싶다.
                Reference
이 문제에 관하여(Swift: 재생 속도를 변경할 수 있는 키프레임 애니메이션), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Kyome/items/15eb1893c48a64900e12텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)