我想在AVPlayerViewController中播放本地视频,但没有找到完成按钮的点击事件。
我的视频可以在AVPlayerViewController中播放,但我没有找到下一个按钮,上一个按钮和完成按钮点击事件。
正式没有Done Button点击事件,Apple的工程师说它here。
至于我的研究,我发现如果单击Done Button,有一种但实际上是间接的方式来获取事件。
我发现AVPlayerViewController的唯一变量是点击完成按钮时更改的是AVPlayerViewController.view.frame
。首先,view.frame出现在viewController的中心。
如果你用animated : true
呈现它,它会转到viewController的底部,然后回到中心。单击完成后,它会返回到底部。
如果你用animated : false
呈现它只会有2个变化:当你开始播放视频时,frame将位于viewController的中心,而当单击Done时,frame将位于底部。
因此,如果你在AVPlayerViewController.view.frame
的回调中将观察者添加到present(PlayerViewController, animated : true)
,你将只获得观察者的一次调用,当点击完成按钮并且视频视图将不在屏幕上时。
在我的例子中,AVPlayerViewController以模态方式呈现动画。以下代码对我有用:
Swift 3.0
override func viewDidLoad()
{
super.viewDidLoad()
let videoURL = NSURL(fileURLWithPath:Bundle.main.path(forResource: "MyVideo", ofType:"mp4")!)
let player = AVPlayer(url: videoURL as URL)
present(playerViewController, animated: false) { () -> Void in
player.play()
self.playerViewController.player = player
self.playerViewController.addObserver(self, forKeyPath: #keyPath(UIViewController.view.frame), options: [.old, .new], context: nil)
}}
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?)
{
print(self.playerViewController.view.frame)
//Player view is out of the screen and
//You can do your custom actions
}
另外,我发现当你单击完成时,AVPlayerViewController没有被解雇,你可以在ParentViewController.presentedViewController
中看到它,所以你不能将观察者添加到这个属性
我这样做是为了从Done
获取AVPlayerViewController
按钮点击事件。
首先,像波纹管一样创建Notification.Name
的扩展
extension Notification.Name {
static let kAVPlayerViewControllerDismissingNotification = Notification.Name.init("dismissing")
}
现在,创建AVPlayerViewController
的扩展并覆盖viewWillDisappear
,如bellow
// create an extension of AVPlayerViewController
extension AVPlayerViewController {
// override 'viewWillDisappear'
open override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// now, check that this ViewController is dismissing
if self.isBeingDismissed == false {
return
}
// and then , post a simple notification and observe & handle it, where & when you need to.....
NotificationCenter.default.post(name: .kAVPlayerViewControllerDismissingNotification, object: nil)
}
}
这只是处理按钮事件的基本功能。
快乐的编码......
这是@vmchar的答案的一个小改进:
我们可以使用.isBeingDismissed方法来确保关闭AVPlayerViewController而不是分析帧。
...
let videoURL = NSURL(fileURLWithPath:"video.mp4")
let player = AVPlayer(url: videoURL as URL)
present(playerViewController!, animated: false) { () -> Void in
player.play()
self.playerViewController!.player = player
self.playerViewController!.addObserver(self, forKeyPath:#keyPath(UIViewController.view.frame), options: [.old, .new], context: nil)
...
然后观察价值
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?)
{
if (playerViewController!.isBeingDismissed) {
// Video was dismissed -> apply logic here
}
}
我有同样的问题,我发现了另一个技巧(与YoutubePlayer swift框架一起工作,在webview中播放视频,但你可能能够适应其他用途)。
在我的情况下,按下Done
按钮并按下全屏视频播放器上的Pause
按钮都会在YoutubePlayer上产生pause
事件。但是,当视频在不同的窗口中播放时,我将应用程序的主窗口子类化,并覆盖了becomeKey
和resignKey
函数来存储我的窗口是否是关键窗口,如下所示:
class MyWindow:UIWindow {
override func becomeKey() {
Services.appData.myWindowIsKey = true
}
override func resignKey() {
Services.appData.myWindowIsKey = false
}
}
一旦我有了,我可以在视频状态暂停时检查我的窗口是否是键 - 当按下Done
按钮时,我的窗口是关键窗口,我可以关闭我的视频视图控制器,在Pause
情况下我的窗口不是关键窗口,所以我什么都不做。
我想有很多方法可以给猫皮肤。我需要处理'完成'点击事件。在我的情况下,我想确保在单击“X”并且AVPlayerViewController完全关闭(解除)后能够挂钩事件。
Swift 4.0
protocol TableViewCellVideoPlayerViewControllerDelegate: class {
func viewControllerDismissed()
}
class MyPlayerViewController: AVPlayerViewController {
weak var navDelegate: TableViewCellVideoPlayerViewControllerDelegate?
open override func viewDidDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed {
self.navDelegate?.viewControllerDismissed()
}
}
}
class TodayCell: UITableViewCell, SFSafariViewControllerDelegate, TableViewCellVideoPlayerViewControllerDelegate {
func viewControllerDismissed() {
self.continueJourney()
}
}
对我来说最简单的解决方案是继承AVPlayerViewController
并为其添加简单的完成块。
class MYVideoController: AVPlayerViewController {
typealias DissmissBlock = () -> Void
var onDismiss: DissmissBlock?
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isBeingDismissed {
onDismiss?()
}
}
}
用法
...
let avPlayerViewController = MYVideoController()
avPlayerViewController.onDismiss = { [weak self] in
print("dismiss")
}
你可以看看这个Stackoverflow post,这里是一个github's project供参考。你将不得不使用这个:
self.showsPlaybackControls = true