我有一个videPlayerView,它上面有ContainerView来显示activityIndicatorView。当我从单元格内的collectionView中选择一个项目时,视图会被加载。我的问题是如何使用cancelButton删除此视图,我为容器和playerView尝试了removeFromSuperview()
但应用程序崩溃时出现此错误
AQDefaultDevice(1):跳过输入流0 0 0x0
以下是代码:
class VideoPlayerView: UIView {
var videoUrl: String!
var uuidd: String!
let activityIndicatorView: UIActivityIndicatorView = {
let aiv = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
aiv.translatesAutoresizingMaskIntoConstraints = false
aiv.startAnimating()
return aiv
}()
lazy var controlsContainerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0, alpha: 1)
view.isUserInteractionEnabled = true
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handlezoomout)))
return view
}()
func handlezoomout(hh: UITapGestureRecognizer){
print("n3me")
}
lazy var cancelButton: UIButton = {
let cancelButton = UIButton()
cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControlState())
cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside)
return cancelButton
}()
func cancel() {
controlsContainerView.removeFromSuperview()
let video = VideoPlayerView()
video.removeFromSuperview()
}
lazy var pausePlayButton: UIButton = {
let button = UIButton(type: .system)
let image = UIImage(named: "pause")
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: "play"), for: UIControlState())
} else {
player?.play()
pausePlayButton.setImage(UIImage(named: "pause"), for: UIControlState())
}
isPlaying = !isPlaying
}
override init(frame: CGRect) {
super.init(frame: frame)
setUpPlayerView()
controlsContainerView.frame = frame
addSubview(controlsContainerView)
cancelButton.frame = CGRect(x: 16.0, y: 20.0, width: 30.0, height: 30.0)
controlsContainerView.addSubview(cancelButton)
controlsContainerView.addSubview(activityIndicatorView)
activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
controlsContainerView.addSubview(pausePlayButton)
pausePlayButton.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
pausePlayButton.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
pausePlayButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
pausePlayButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
backgroundColor = UIColor.black
}
var player: AVPlayer?
fileprivate func setUpPlayerView() {
let postQuery = PFQuery(className: "posts")
postQuery.whereKey("uuid", equalTo: PostUuidGlobalVariable.postuuid.last!)
postQuery.getFirstObjectInBackground { (object, error) in
if (error == nil && object != nil) {
let videoFile = object!["video"] as! PFFile
if let url = URL (string: videoFile.url!) {
self.player = AVPlayer(url: url)
let playerLayer = AVPlayerLayer(player: self.player)
self.layer.addSublayer(playerLayer)
playerLayer.frame = self.frame
self.player?.play()
self.player?.isMuted = false
self.player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.playerDidFinishPlaying(note:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
}
}
}
}
func playerDidFinishPlaying(note: NSNotification) {
}
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()
pausePlayButton.isHidden = false
isPlaying = true
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class VideoLauncher: NSObject {
func showVideoPlayer() {
if let keyWindow = UIApplication.shared.keyWindow {
let view = UIView(frame: keyWindow.frame)
view.isUserInteractionEnabled = true
view.backgroundColor = UIColor.white
view.frame = CGRect(x: keyWindow.frame.width - 10, y: keyWindow.frame.height - 10, width: 10, height: 10)
let height = keyWindow.frame.height
let videoPlayerFrame = CGRect(x: 0, y: 0, width: keyWindow.frame.width, height: height)
let videoPlayerView = VideoPlayerView(frame: videoPlayerFrame)
view.addSubview(videoPlayerView)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
view.frame = keyWindow.frame
}, completion: { (completedAnimation) in
//maybe we'll do something here later...
UIApplication.shared.isStatusBarHidden = true
})
keyWindow.addSubview(view)
}
}
}
答案 0 :(得分:0)
这有可能与您更改主线程之外的用户界面有关。
来自UIView文件
'线程注意事项
必须在主线程上对应用程序的用户界面进行操作。因此,你应该总是调用方法
的UIView
来自应用程序主线程中运行的代码的类。这可能不是绝对必要的唯一时间是创建视图对象本身,但所有其他操作应该在主线程上发生。'
此外,您的取消功能会创建一个新的视频播放器视图,然后尝试将其从父视图中删除,这看起来不正确。
您的取消回调应该如下
func cancel() {
DispatchQueue.main.async { [unowned self] in
// to remove controls
self.controlsContainerView.removeFromSuperview()
// to remove video player view
self.view.removeFromSuperview()
}
}