Готово событие нажатия кнопки в AVPlayerViewController
Я хочу воспроизвести локальное видео в AVPlayerViewController, но не нашел событие нажатия кнопки "Готово".
Мое видео может воспроизводиться в AVPlayerViewController, но я не нашел следующую кнопку, предыдущую кнопку и событие готового нажатия кнопки.
5 ответов
Я сделал это, чтобы получить Done
событие нажатия кнопки от AVPlayerViewController
,
Прежде всего, создайте расширение Notification.Name
как ниже
extension Notification.Name {
static let kAVPlayerViewControllerDismissingNotification = Notification.Name.init("dismissing")
}
Теперь создайте расширение AVPlayerViewController
и переопределить viewWillDisappear
как ниже
// 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)
}
}
ЭТО ТОЛЬКО ДЛЯ ОСНОВНОЙ ФУНКЦИОНАЛЬНОСТИ, КОТОРАЯ ОБРАЩАЕТСЯ К СОБЫТИЮ КНОПОК.
счастливое кодирование...
Официально не происходит событие нажатия кнопки "Готово", об этом здесь сказал инженер из Apple.
Что касается моего исследования, я обнаружил, что есть один, но действительно косвенный способ получить событие, если нажать кнопку "Готово".
Я обнаружил, что единственная переменная AVPlayerViewController, которая изменяется при нажатии кнопки "Готово", AVPlayerViewController.view.frame
, Прежде всего view.frame появляется в центре viewController.
Если вы представите это с animated : true
это идет к нижней части viewController и обратно к центру. Когда готово будет нажата, он возвращается к основанию.
Если вы представите это с animated : false
будет только 2 изменения: рамка будет в центре viewController, когда вы начнете воспроизводить видео, и внизу, когда нажмете "Готово".
Так что, если вы добавите наблюдателя к 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
, поэтому вы не можете добавить наблюдателя к этому свойству
Объективная версия c: (на основе ответа vmchar)
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:path];
AVPlayer *player = [AVPlayer playerWithURL:url];
AVPlayerViewController *AVPlayerVc = [[AVPlayerViewController alloc] init];
if (AVPlayerVc) {
[self presentViewController:AVPlayerVc animated:YES completion:^{
[player play];
AVPlayerVc.player = player;
[AVPlayerVc addObserver:self forKeyPath:@"view.frame" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:nil];
}];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"view.frame"]) {
CGRect newValue = [change[NSKeyValueChangeNewKey]CGRectValue];
CGFloat y = newValue.origin.y;
if (y != 0) {
NSLog(@"Video Closed");
}
}
}
Самым простым решением для меня было создание подкласса 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")
}
Это небольшое улучшение по сравнению с ответом @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
}
}
Я нашел обходной путь, не создавая подкласс AVPlayerViewController
, что в документации четко указано, что вы не должны этого делать ( https://developer.apple.com/documentation/avkit/avplayerviewcontroller). Это некрасиво, но он выполнил свою работу за меня, предоставив мне место для запуска кода, когдаAVPlayerViewController
уволен.
AnyViewController: UIViewController, AVPlayerViewControllerDelegate {
private let playerVC = AVPlayerViewController()
override func viewDidLoad() {
playerVC.delegate = self
}
func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if playerViewController.isBeingDismissed {
playerViewController.dismiss(animated: false) { [weak self] in
self?.someDismissFunc()
}
}
}
}
Насколько я могу судить, это действительно запутано, что нет чистого способа сделать это:(
Я думаю, что есть много способов снять шкуру с кошки. Мне нужно было обработать событие клика "Готово". В моем случае я хотел убедиться, что я смог подключиться к событию после нажатия кнопки "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()
}
}
У меня была та же проблема, и я нашел другой прием (работает с YoutubePlayer Swift Framework, который воспроизводит видео в веб-просмотре, но вы можете адаптировать его для других целей).
В моем случае нажатие Done
кнопку и нажав Pause
Кнопка на полноэкранном видеоплеере приводит к pause
событие на YoutubePlayer. Однако, поскольку видео воспроизводится в другом окне, я переклассифицировал главное окно своего приложения и переопределил becomeKey
а также resignKey
функции для хранения, является ли мое окно ключевым окном или нет, вот так:
class MyWindow:UIWindow {
override func becomeKey() {
Services.appData.myWindowIsKey = true
}
override func resignKey() {
Services.appData.myWindowIsKey = false
}
}
После этого я могу проверить, является ли мое окно ключевым, когда состояние видео переходит в режим паузы - когда Done
кнопка была нажата, мое окно является ключевым окном, и я могу закрыть свой контроллер просмотра видео, и в Pause
В этом случае мое окно не является ключевым, поэтому я ничего не делаю.
Вы можете заглянуть в этот пост Stackru, и вот проект github для справки. Вам придется использовать это:
self.showsPlaybackControls = true
Пожалуйста, ознакомьтесь с документацией Apple.