简体   繁体   中英

animating a CALayer

I have a CALayer on top of a UIView.

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.

I was wondering if there was any property of CALayers that could handle this issue automatically but I haven't found anything.

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 .

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:

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. 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:

        playerView?.playerLayer = player

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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