Заблокировать событие нажатия кнопки в AVPlayerViewController

Я хочу воспроизвести локальное видео в AVPlayerViewController, но не нашел событие нажатия кнопки "Готово".

Мое видео может воспроизводиться в AVPlayerViewController, но я не нашел следующую кнопку, предыдущую кнопку и событие нажатия кнопки мыши.

Ответ 1

Официально нет события щелчка кнопки Done Button, об этом сказал инженер из 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, поэтому вы не можете добавить наблюдателя в это свойство

Ответ 2


Я сделал это, чтобы получить событие нажатия кнопки 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)
    }
}

ЭТО ДЛЯ ТОЛЬКО ОСНОВНОЙ ФУНКЦИОНАЛЬНОСТИ, КОТОРЫЕ РАБОТАЮТ СОБЫТИЮ СОВМЕСТНОГО КНОПКА.

счастливое кодирование...

Ответ 3

Это небольшое улучшение от ответа @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
    } 
} 

Ответ 4

Самым простым решением для меня было создать подкласс AVPlayerViewController и добавить в него простой блок завершения.

class MYVideoController: AVPlayerViewController {

  typealias DissmissBlock = () -> Void
  var onDismiss: DissmissBlock?

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if isBeingDismissed {
      onDismiss?()
    }
  }
}

Usage

Usage
...
let avPlayerViewController = MYVideoController()
avPlayerViewController.onDismiss = { [weak self] in 
    print("dismiss")
}

Ответ 5

Вы можете использовать

override func viewWillAppear(_ animated: Bool) { print("Done Button Click Event") }

В вашем классе. Когда AVPlayerViewController исчезнет, ​​тогда вызовите funWillAppear func, и вы можете сделать свою работу здесь.

Если вы используете класс AVPlayerViewController, вы можете использовать эту функцию.

override func viewWillDisappear(_ animated: Bool) { <#code#> }

Ответ 6

У меня была та же проблема, и я нашел еще один трюк (работает с быстрой платформой YoutubePlayer, которая воспроизводит видео в веб-просмотре, но вы можете адаптировать его к другим приложениям).

В моем случае нажатие кнопки 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 мое окно не в ключевом окне, поэтому я ничего не делаю.

Ответ 7

Я думаю, что есть много способов снять кожу с кошки. Мне нужно было обработать событие клика "Готово". В моем случае я хотел убедиться, что я смог подключиться к событию после нажатия кнопки "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()
    }
 }

Ответ 8

Целевая версия 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");
        }
     }
}