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

下面的代码将视频播放器动画显示在屏幕上,并在视频视图中包含AVPlayer并开始播放视频剪辑。

但是,当我按下dismissButton时,它不起作用。它仅隐藏dismissButton。

感谢您帮助我解决此问题的任何帮助。

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

最佳答案

轻按“关闭”按钮时,仅从 super 视图中删除controlsContainerView

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

鉴于您的安装方式,我将执行以下操作:
  • 您不需要在let view = ...内添加showVideoPlayer,而只需使用videoPlayerView并将其添加为keyWindow.addSubView(videoPlayerView)
  • pressButton中,您必须首先从添加的player中删除观察者,例如player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
  • 仍在pressButton内像player?.stop()一样停止播放器,然后像您对self的操作一样从 super 视图中删除self.removeFromSuperview()

  • 注意:我不喜欢视图本身应该负责将自己从 super 视图中删除。因此,我建议您使用一个控制器来处理VideoPlayerView的显示/隐藏,并仅向VideoPlayerView添加一个 public 方法(如stop),在其中您将删除player的所有观察者,停止player,以便当控制器决定删除VideoPlayerView时,您将执行此操作一个很好的清理

    08-18 17:53