动画 CALayer
Posted
技术标签:
【中文标题】动画 CALayer【英文标题】:animating a CALayer 【发布时间】:2017-06-19 03:07:38 【问题描述】:我在 UIView 之上有一个 CALayer。
UIView 的动画效果完全符合我的要求,但其顶部的 PlayerView 似乎在屏幕外“生成”然后动画到 UIView 在 然后 开始的位置 它将动画到 UIViews 框架。
我想知道 CALayers 是否有任何属性可以自动处理这个问题,但我没有找到任何东西。
下面是代码:
let window = UIApplication.shared.keyWindow!
v = UIView(frame: CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.width, height: window.frame.height))
let v2 = UIView(frame: .zero)
window.addSubview(v!);
window.addSubview(v2)
v?.backgroundColor = UIColor.black
v2.backgroundColor = UIColor.clear
v?.layer.cornerRadius = (v?.frame.width)! * 0.025
guard let path = Bundle.main.path(forResource: "video", ofType:"mp4") else
debugPrint("video.m4v not found")
return
player = AVPlayer(url: URL(fileURLWithPath: path))
playerLayer = AVPlayerLayer(player: player)
// playerLayer.frame = playerView.frame
playerLayer?.frame = (playerView?.bounds)!
playerLayer?.masksToBounds = true
playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
v?.layer.addSublayer(playerLayer!)
player?.play()
player?.isMuted = true
//looper
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil)
notification in
let t1 = CMTimeMake(5, 100)
self.player?.seek(to: t1)
self.player?.play()
let superview = playerView?.superview
v2.frame = (v2.convert((playerView?.frame)!, from: superview))
v?.frame = (v?.convert((playerView?.frame)!, from: superview))!
window.addConstraintsWithFormat("H:|[v0]|", views: v!)
window.addConstraintsWithFormat("V:|[v0]|", views: v!)
playerLayer?.frame = (v?.frame)!
self.playerLayer?.frame = (self.v?.frame)!
UIView.animate(withDuration: 4, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations:
self.window?.layoutIfNeeded()
, completion: (completed) in
self.playerLayer?.frame = (self.v?.frame)!
)
有什么建议吗?
编辑:
我已经包含了更新的代码
let window = UIApplication.shared.keyWindow!
v = UIView(frame: CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.width, height: window.frame.height))
let v2 = UIView(frame: .zero)
window.addSubview(v!);
v?.addSubview(playerView2!)
window.addSubview(v2)
v?.backgroundColor = UIColor.black
v2.backgroundColor = UIColor.clear
v?.layer.cornerRadius = (v?.frame.width)! * 0.025
playerView2?.layer.cornerRadius = (playerView2?.bounds.width)! * 0.025
guard let path = Bundle.main.path(forResource: "video", ofType:"mp4") else
debugPrint("video.m4v not found")
return
player = AVPlayer(url: URL(fileURLWithPath: path))
playerLayer = AVPlayerLayer(player: player)
// playerLayer.frame = playerView.frame
playerLayer?.frame = (playerView2?.bounds)!
playerLayer?.masksToBounds = true
playerLayer?.cornerRadius = (playerView2?.bounds.width)! * 0.025
playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
self.playerView2?.layer.addSublayer(playerLayer!)
// player?.play()
player?.isMuted = true
//looper
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil)
notification in
let t1 = CMTimeMake(5, 100)
self.player?.seek(to: t1)
// self.player?.play()
self.playerView2?.frame = (self.v?.bounds)!
self.playerLayer?.frame = (self.playerView?.bounds)!
UIView.animate(withDuration: 5, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations:
self.v?.frame = window.frame
self.playerView2?.frame = (self.v?.frame)!
self.playerLayer?.frame = (self.playerView2?.frame)!
self.window?.layoutIfNeeded()
, completion: (completed) in
)
【问题讨论】:
【参考方案1】:当您设置playerLayer.frame
时,您将获得一个隐式动画。
如果您不想要任何动画,请暂时禁用隐式动画,如下所示:
UIView.animate(withDuration: 4, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations:
self.window?.layoutIfNeeded()
, completion: (completed) in
let priorValue = CATransaction.disableActions()
CATransaction.setDisableActions(true)
self.playerLayer?.frame = self.v!.frame
CATransaction.setDisableActions(priorValue)
)
如果您确实想要为playerLayer.frame
设置动画,那么最好的方法是创建一个使用AVPlayerLayer
作为其层的UIView
子类,如下所示:
class PlayerView: UIView
override class var layerClass: AnyClass return AVPlayerLayer.self
private(set) lazy var playerLayer: AVPlayerLayer = self.layer as! AVPlayerLayer ()
然后您可以使用PlayerView
而不是裸露的AVPlayerLayer
并使用UIKit 动画。由于您不能直接初始化AVPlayerLayer
(UIView
使用默认初始化程序来创建其层),您需要像这样设置PlayerView
的播放器:
playerView?.playerLayer = player
【讨论】:
我能够使用您的第二个建议并将 UIView 与 AVPlayer 一起使用,但是,UIView 和 PlayerLayer 仍然不能一致地制作动画。每当我尝试强制动画时,playerLayer 都会正确地掩蔽到 UIView,但这是一个尴尬的跳跃,而不是平滑的动画。还有什么建议吗? 我需要查看您修改后的代码,并更好地描述您不喜欢的情况。 它有点工作,只是 playerLayer 没有与 v 和 playerView 一起动画......另外两个动画完美地一致。当前的行为就像self.playerLayer?.frame = (self.playerView2?.frame)!
行在其他两个开始动画后读取一两秒,因此它跳到帧而不是平滑地为过渡设置动画。以上是关于动画 CALayer的主要内容,如果未能解决你的问题,请参考以下文章