在AVPlayerViewController中完成按钮单击事件

时间:2016-07-25 10:32:53

标签: ios objective-c avplayer avplayerviewcontroller

我想在AVPlayerViewController中播放本地视频,但未找到完成按钮的点击事件。

我的视频可以在AVPlayerViewController中播放,但我没有找到下一个按钮,上一个按钮和完成按钮点击事件。

9 个答案:

答案 0 :(得分:15)

官方没有完成按钮点击事件,Apple的工程师说了here

至于我的研究,我发现如果单击完成按钮,有一种但实际上是间接的方式来获取事件。

我发现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
}

另外,我发现当你点击Done时,AVPlayerViewController没有被解雇,你可以在ParentViewController.presentedViewController看到它,所以你不能将观察者添加到这个属性

答案 1 :(得分:13)


我这样做是为了从Done获取AVPlayerViewController按钮点击事件。

首先,创建Notification.Name的扩展名,如bellow

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)
    }
}

这仅仅是处理按钮事件的基本功能。

快乐的编码......

答案 2 :(得分:2)

目标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");
        }
     }
}

答案 3 :(得分:1)

这是@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 :(得分:1)

我找到了一种解决方法,而不必将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()
            }
        }
    }
}

据我所知:(

答案 5 :(得分:0)

我遇到了同样的问题,我发现了另一个技巧(适用于在webview中播放视频的YoutubePlayer swift框架,但您可以将其调整为其他用途)。

在我的情况下,按下Done按钮并按全屏视频播放器上的Pause按钮都会在YoutubePlayer上产生pause事件。但是,当视频在不同的窗口中播放时,我将应用程序的主窗口子类化,并覆盖becomeKeyresignKey函数来存储我的窗口是否是关键窗口,如下:

class MyWindow:UIWindow {
    override func becomeKey() {
        Services.appData.myWindowIsKey = true
    }

    override func resignKey() {
        Services.appData.myWindowIsKey = false
    }
}

有了这个,我可以在视频状态暂停时查看我的窗口是否为按键 - 当按下Done按钮时,我的窗口 是关键窗口我可以解雇我的视频视图控制器,在Pause情况下,我的窗口不是关键窗口,所以我什么都不做。

答案 6 :(得分:0)

我想有很多方法可以给猫皮。我需要处理“完成”点击事件。就我而言,我想确保在单击“ 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()
    }
 }

答案 7 :(得分:0)

对我来说,最简单的解决方案是将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")
}

答案 8 :(得分:-5)

您可以查看此Stackoverflow post,此处是github's project以供参考。你必须使用它:

 self.showsPlaybackControls = true

请同时查看Apple's documentation