如何从superView中删除自定义playerView?
问题描述:
我有一个videPlayerView,它上面有ContainerView来显示activityIndicatorView。当我从单元格中的一个collectionView中选择一个项目时,该视图被加载。我的问题是如何使用cancelButton以除去这种观点,我试图removeFromSuperview()
用于容器都和playerView但与此错误如何从superView中删除自定义playerView?
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)
}
}
}
答
有这关系到你改变主线程之外的用户界面的机会。
从UIView的文件
“线程注意事项
手法到应用程序的用户界面在主线程必须发生。因此,您应该始终使用应用程序主线程中运行的代码调用类的方法。唯一可能不是严格需要的是创建视图对象本身,但所有其他操作应该在主线程上进行。
此外,您的取消功能会创建一个新的视频播放器视图,然后尝试将其从它看起来不正确的父视图中移除。
你取消回调大概应该是如下
func cancel() {
DispatchQueue.main.async { [unowned self] in
// to remove controls
self.controlsContainerView.removeFromSuperview()
// to remove video player view
self.view.removeFromSuperview()
}
}
感谢您的回答SPAD的。我得到一个编译器错误为self.view(价值的类型VideoplayerView没有成员视图。我试图直接删除VideoplayerView但我得到了错误。终止与未捕获异常类型NSException – user8249883
是'视图'是一个错字。应该可以从ViewController管理VideoPlayerView的可见性而不是视图本身,崩溃很可能是由于你在运行代码的时候删除了视图 – Spads
是的,这个问题我最终实现了UIPanGesturerecognizer,就像在youtube上一样现在它终于有效了,谢谢。 – user8249883