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