Ios AVPlayer无法关闭该视图

Ios AVPlayer无法关闭该视图,ios,swift,Ios,Swift,我正在创建一个允许用户观看视频的功能 使用下面的代码,它可以在屏幕上设置视频播放器的动画,并在视频视图中包含一个AVPlayer,然后开始播放视频剪辑 但是,当我按下DISMISS按钮时,它不工作。它只隐藏了一个按钮 我感谢任何帮助我解决这个问题 import UIKit import AVFoundation class VideoPlayerView: UIView { let activityIndicatorView: UIActivityIndicatorView = {

我正在创建一个允许用户观看视频的功能

使用下面的代码,它可以在屏幕上设置视频播放器的动画,并在视频视图中包含一个AVPlayer,然后开始播放视频剪辑

但是,当我按下DISMISS按钮时,它不工作。它只隐藏了一个按钮

我感谢任何帮助我解决这个问题

import UIKit
import AVFoundation

class VideoPlayerView: UIView {


    let activityIndicatorView: UIActivityIndicatorView = {
        let aiv = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
        aiv.translatesAutoresizingMaskIntoConstraints = false
        aiv.startAnimating()
        return aiv
    }()

    lazy var pausePlayButton: UIButton = {
        let button = UIButton(type: .system)
        let image = UIImage(named: "pauseButton")
        button.setImage(image, for: UIControlState())
        button.translatesAutoresizingMaskIntoConstraints = false
        button.tintColor = .white
        button.isHidden = true

        button.addTarget(self, action: #selector(handlePause), for: .touchUpInside)

        return button
    }()

    var isPlaying = false

    func handlePause() {
        if isPlaying {
            player?.pause()
            pausePlayButton.setImage(UIImage(named: "playVideoButton"), for: UIControlState())
        } else {
            player?.play()
            pausePlayButton.setImage(UIImage(named: "pauseButton"), for: UIControlState())
        }

        isPlaying = !isPlaying
    }

    let controlsContainerView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor(white: 0, alpha: 1)
        return view
    }()

    let dismissButton: UIButton = {
        let button = UIButton(type: .system)
        let image = UIImage(named: "closeVideoButton")
        button.setImage(image, for: UIControlState())
        button.translatesAutoresizingMaskIntoConstraints = false
        button.tintColor = .white
        button.addTarget(self, action:#selector(pressButton(button:)), for: .touchUpInside)

        return button
    }()

    func pressButton(button: UIButton) {
        controlsContainerView.removeFromSuperview()

        self.removeFromSuperview()
    }




    let currentTimeLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "0:00"
        label.textColor = .white
        label.font = UIFont.boldSystemFont(ofSize: 17)
        return label
    }()

    lazy var videoSlider: UISlider = {
        let slider = UISlider()
        slider.translatesAutoresizingMaskIntoConstraints = false
        slider.minimumTrackTintColor = .white
        slider.maximumTrackTintColor = .lightGray
        slider.setThumbImage(UIImage(named: "thumb"), for: UIControlState())

        slider.addTarget(self, action: #selector(handleSliderChange), for: .valueChanged)

        return slider
    }()

    func handleSliderChange() {
        print(videoSlider.value)

        if let duration = player?.currentItem?.duration {
            let totalSeconds = CMTimeGetSeconds(duration)

            let value = Float64(videoSlider.value) * totalSeconds

            let seekTime = CMTime(value: Int64(value), timescale: 1)

            player?.seek(to: seekTime, completionHandler: { (completedSeek) in
            })
        }
    }



    override init(frame: CGRect) {
        super.init(frame: frame)

        setupPlayerView()

        setupGradientLayer()


        controlsContainerView.frame = frame
        addSubview(controlsContainerView)

        controlsContainerView.addSubview(activityIndicatorView)
        activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true

        controlsContainerView.addSubview(pausePlayButton)
        pausePlayButton.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        pausePlayButton.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
        pausePlayButton.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
        pausePlayButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

        controlsContainerView.addSubview(currentTimeLabel)
        currentTimeLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true
        currentTimeLabel.topAnchor.constraint(equalTo: topAnchor, constant: -2).isActive = true
        currentTimeLabel.widthAnchor.constraint(equalToConstant: 50).isActive = true
        currentTimeLabel.heightAnchor.constraint(equalToConstant: 44).isActive = true

        controlsContainerView.addSubview(dismissButton)
        dismissButton.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true
        dismissButton.topAnchor.constraint(equalTo: topAnchor, constant: -2).isActive = true
        dismissButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
        dismissButton.heightAnchor.constraint(equalToConstant: 44).isActive = true

        controlsContainerView.addSubview(videoSlider)
        videoSlider.rightAnchor.constraint(equalTo: currentTimeLabel.leftAnchor).isActive = true
        videoSlider.topAnchor.constraint(equalTo: topAnchor).isActive = true
        videoSlider.leftAnchor.constraint(equalTo: dismissButton.rightAnchor).isActive = true
        videoSlider.heightAnchor.constraint(equalToConstant: 40).isActive = true

        backgroundColor = .black
    }

    var player: AVPlayer?

    fileprivate func setupPlayerView() {
        let urlString = "https://firebasestorage.googleapis.com/v0/b/bunpou-d20ae.appspot.com/o/katoomouto.mp4?alt=media&token=861a0bad-2979-428c-94cf-f86dc9cb63ca"
        if let url = URL(string: urlString) {
            player = AVPlayer(url: url)

            let playerLayer = AVPlayerLayer(player: player)
            self.layer.addSublayer(playerLayer)
            playerLayer.frame = self.frame

            player?.play()

            player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)

            //track player progress

            let interval = CMTime(value: 1, timescale: 2)
            player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { (progressTime) in

                let seconds = CMTimeGetSeconds(progressTime)
                let secondsString = String(format: "%02d", Int(seconds.truncatingRemainder(dividingBy: 60)))
                let minutesString = String(format: "%02d", Int(seconds / 60))

                self.currentTimeLabel.text = "\(minutesString):\(secondsString)"

                if let duration = self.player?.currentItem?.duration {
                    let durationSeconds = CMTimeGetSeconds(duration)

                    self.videoSlider.value = Float(seconds / durationSeconds)

                }

            })
        }
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

        //this is when the player is ready and rendering frames
        if keyPath == "currentItem.loadedTimeRanges" {
            activityIndicatorView.stopAnimating()
            controlsContainerView.backgroundColor = .clear
            pausePlayButton.isHidden = false
            isPlaying = true


        }
    }

    fileprivate func setupGradientLayer() {
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = bounds
        gradientLayer.colors = [UIColor.black.cgColor, UIColor.clear.cgColor]
        gradientLayer.locations = [-1.4, 0.2]
        controlsContainerView.layer.addSublayer(gradientLayer)
    }



    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class VideoLauncher: NSObject {

    func showVideoPlayer() {
        print("Showing video player animation....")

        if let keyWindow = UIApplication.shared.keyWindow {
            let view = UIView(frame: keyWindow.frame)
            view.backgroundColor = UIColor.white

            view.frame = CGRect(x: keyWindow.frame.width - 10, y: keyWindow.frame.height - 10, width: 10, height: 10)

            let videoPlayerFrame = CGRect(x: 0, y: 0, width: keyWindow.frame.width, height: keyWindow.frame.height)
            let videoPlayerView = VideoPlayerView(frame: videoPlayerFrame)
            view.addSubview(videoPlayerView)

            keyWindow.addSubview(view)

            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {

                view.frame = keyWindow.frame

            }, completion: { (completedAnimation) in
            })
        }
    }
}

点击“解除”按钮时,您只能从superview中删除
控件ContainerView

func pressButton(button: UIButton) { controlsContainerView.removeFromSuperview() }
考虑到您的设置方式,我将执行以下操作:

  • 您不需要在
    showVideoPlayer
    中使用
    let view=…
    ,只需使用
    videoPlayerView
    并像
    keyWindow.addSubView(videoPlayerView)
  • 内按按钮
    您必须首先从您添加的
    player
    中删除观察者,如
    player?.addObserver(self,forKeyPath:“currentItem.loadedTimeRanges”,选项:。新建,上下文:nil)
  • 仍在
    内按按钮
    停止播放器,如
    player?.stop()
    ,然后从superview中删除
    self
    ,就像您使用
    self.removeFromSuperview()

  • 注意:我不喜欢视图本身应该负责从superview中删除自己。因此,我建议您使用一个控制器来处理
    VideoPlayerView
    的显示/隐藏,只需在
    VideoPlayerView
    中添加一个公共方法,如
    stop
    ,这样您就可以删除
    播放器的所有观察者,停止
    播放器
    ,这样当控制器决定删除
    VideoPlayerView
    时,您将进行一次很好的清理

    包括显示如何将AVPlayer添加为子视图(可能为AVPlayerLayer)的代码。是的,我添加了代码。好的,检查答案,当我添加方法时,您没有从视图层次中删除AVPlayerLayer“playerLayer.removeFromSuperlayer()”我收到错误“未解析标识符”的使用“playerLayer”你有什么想法吗?我只是在一个测试应用程序中这样做,它删除了playerLayer,将pressButton方法更新为您当前拥有的方法。还请检查let playerLayer在哪里被清除…它是在VideoPlayerView类中还是在其他地方?我更新了答案playerLayer在“VideoLauncher类”中被清除。感谢您的帮助:)