简体   繁体   English

为CALayer设置动画

[英]animating a CALayer

I have a CALayer on top of a UIView. 我在UIView上有一个CALayer。

The UIView animates exactly how I want it to, however the PlayerView that is on top of it seems to "spawn" offscreen then animate to the position that the UIView started in and then it will animate to the UIViews frame. UIView的动画正是我想要它,但是这是在它之上的PlayerView似乎“重生”离屏幕动画,然后到了UIView中开始,然后它会以动画的UIViews帧中的位置。

I was wondering if there was any property of CALayers that could handle this issue automatically but I haven't found anything. 我想知道是否有CALayers的任何属性可以自动处理此问题,但我什么都没找到。

Here's the code for this: 这是此代码:

    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)!



    })


}

any suggestions? 有什么建议么?

EDIT: 编辑:

I have included the updated code 我已包含更新的代码

    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




    })





}

You're getting an implicit animation when you set playerLayer.frame . 设置playerLayer.frame时,您将获得一个隐式动画。

If you don't want any animation, temporarily disable implicit animations like this: 如果您不想使用任何动画,请暂时禁用如下所示的隐式动画:

        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)
        })

If you do want to animate playerLayer.frame , then the best way is to create a UIView subclass that uses an AVPlayerLayer as its layer, like this: 如果您想为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 }()
}

Then you can use a PlayerView instead of a bare AVPlayerLayer and use UIKit animations. 然后,您可以使用PlayerView代替裸露的AVPlayerLayer并使用UIKit动画。 Since you can't initialize the AVPlayerLayer directly ( UIView uses the default initializer to create its layer), you'll need to set the PlayerView 's player like this: 由于您无法直接初始化AVPlayerLayerUIView使用默认的初始化程序创建其图层),因此需要像这样设置PlayerView的播放器:

        playerView?.playerLayer = player

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM