如何拦截在AVPlayerViewController中完成button的点击?

我在自定义的UIViewControllerviewDidAppear方法中创build了一个AVPlayerViewController和一个附加的AVPlayer 。 但是,当我按下“完成”button,我的自定义视图控制器被自动解雇。

我想拦截这个动作,以便使用我自己的解除Segue,但我不知道如何做到这一点。 我find了MPMoviePlayerViewController例子,但不是AVPlayerViewController

我为MPMoviePlayerViewControllerfind的代码如下:

 - (void)playVideo:(NSString *)aVideoUrl { // Initialize the movie player view controller with a video URL string MPMoviePlayerViewController *playerVC = [[[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:aVideoUrl]] autorelease]; // Remove the movie player view controller from the "playback did finish" notification observers [[NSNotificationCenter defaultCenter] removeObserver:playerVC name:MPMoviePlayerPlaybackDidFinishNotification object:playerVC.moviePlayer]; // Register this class as an observer instead [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieFinishedCallback:) name:MPMoviePlayerPlaybackDidFinishNotification object:playerVC.moviePlayer]; // Set the modal transition style of your choice playerVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; // Present the movie player view controller [self presentModalViewController:playerVC animated:YES]; // Start playback [playerVC.moviePlayer prepareToPlay]; [playerVC.moviePlayer play]; } - (void)movieFinishedCallback:(NSNotification *)aNotification { // Obtain the reason why the movie playback finished NSNumber *finishReason = [[aNotification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey]; // Dismiss the view controller ONLY when the reason is not "playback ended" if ([finishReason intValue] != MPMovieFinishReasonPlaybackEnded) { MPMoviePlayerController *moviePlayer = [aNotification object]; // Remove this class from the observers [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer]; // Dismiss the view controller [self dismissModalViewControllerAnimated:YES]; } } 

我问苹果这个问题,他们回答如下:

感谢您联系Apple开发者技术支持(DTS)。 我们的工程师已经审查了您的要求,并得出结论认为,在目前的运输系统configuration下,没有支持的方式来实现所需的function。

我subclassed AVPlayerViewController,并发布来自viewWillDisappear的通知,以表明解散AVPlayerViewController。

 - (void) viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerViewDismissedNotification object:nil]; [super viewWillDisappear:animated]; } 

这可能不是100%正确的(因为在AVPlayerViewController上显示另一个视图时会失败),但是AVPlayerViewController始终位于堆栈的顶部,所以对我来说是正确的。

苹果没有提供内置的方式来处理完成button的事实令人失望。

我不觉得从AVPlayerViewControllerinheritance,因为它不被苹果支持,并可能会在下一个iOS更新之一打开一jar蠕虫。

我的解决方法是每200毫秒有一个定时器触发,并检查以下情况:

 if (playerVC.player.rate == 0 && (playerVC.isBeingDismissed || playerVC.nextResponder == nil)) { // Handle user Done button click and invalidate timer } 

玩家的rate属性为0表示video不再播放。 如果视图控制器被解散或已经被解雇,我们可以安全地假定用户点击了完成button。

你可以通过inheritanceAVPLayerViewController来完成。 但是由于这个原因还有一些不确定的行为。 (在苹果文档中给出。见下文)我也试过子类AVPlayerViewController和我面临内存问题。

根据苹果文件:

不要inheritanceAVPlayerViewController。 覆盖此类的方法不受支持,并导致未定义的行为。

目前,当AVPlayerViewController被解雇时,他们不提供callback。 查看苹果开发者论坛:

  • 线程1
  • 线程2

在thread1中苹果的家伙说:

我仍然相信,通过使用上面推荐的手势方法来手动pipe理AVPlayerViewController实例的退出将是知道玩家视图控制器已被解散的最可靠的方式,因为您将在此时负责解雇

希望能帮助到你!


那么问题就解决了。 您可以添加一个button作为AVPlayerViewController的子视图。 通过这样做,你可以拦截完button点击手势。

由于这里似乎没有任何完美的答案,所以在某些情况下可以使用的解决方法是监视AVPlayer是否仍在播放并设置观看者,以防播放完毕后自动closures。

  var player:AVPlayer = AVPlayer() var videoPlayTimer:NSTimer = NSTimer() func playVideo(action: UIAlertAction) -> Void { player = AVPlayer(URL: NSURL(fileURLWithPath: myFilePath)) player.actionAtItemEnd = .None let playerController = AVPlayerViewController() playerController.player = player self.presentViewController(playerController, animated: true) { self.player.play() self.monitorVideoPlayStatus() NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.onVideoEnd(_:)), name: AVPlayerItemDidPlayToEndTimeNotification, object: self.player.currentItem) } } //setting a timer to monitor video play status in case it is closed by user func monitorVideoPlayStatus(){ if ((player.rate != 0) && (player.error == nil)) { NSLog("player is playing") videoPlayTimer = NSTimer.after(0.5, monitorVideoPlayStatus) } else { NSLog("player is NOT playing") onVideoEnd() } } //will be called when video plays all the way through func onVideoEnd(note: NSNotification){ NSLog("onVideoEnd") onVideoEnd() //canceling video play monitor videoPlayTimer.invalidate() } func onVideoEnd(){ NSLog("finished playing video") NSNotificationCenter.defaultCenter().removeObserver(self, name: AVPlayerItemDidPlayToEndTimeNotification, object: nil) //******* //DO WHATEVER YOU WANT AFTER VIDEO HAS ENDED RIGHT HERE //******* } 

这里是我如何设法检测点击的代码。

在应用程序委托类。 但它会检测在该视图中find的每个button。 你可以添加一些控制,检查标题类似的东西。

 -(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{ if ([window.rootViewController isKindOfClass:[AVPlayerViewController class]]) { return UIInterfaceOrientationMaskAll; } else if(window.rootViewController.presentedViewController != nil) { if ([window.rootViewController.presentedViewController isKindOfClass:[AVPlayerViewController class]] || [window.rootViewController.presentedViewController isKindOfClass:NSClassFromString(@"AVFullScreenViewController")]) { if ([window.rootViewController.presentedViewController isKindOfClass:NSClassFromString(@"AVFullScreenViewController")]) { [self findAllButton:window.rootViewController.presentedViewController.view]; } return UIInterfaceOrientationMaskAll; } } [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"]; [[UIApplication sharedApplication] setStatusBarHidden:NO]; return UIInterfaceOrientationMaskPortrait; } -(void)findAllButton:(UIView*)view{ for (UIView *subV in view.subviews) { if ([subV isKindOfClass:[UIButton class]]) { NSLog(@"%@",[((UIButton*)subV) titleForState:UIControlStateNormal]); [((UIButton*)subV) addTarget:self action:@selector(doneButtonCliked) forControlEvents:UIControlEventTouchUpInside]; } else{ [self findAllButton:subV]; } } } -(IBAction)doneButtonCliked{ NSLog(@"DONECLICK"); } 

如果你有一个呈现AVPlayerViewController的视图控制器A,你可以在VC A中检查viewDidAppear / viewWillAppear。每当调用这些视图时,至less我们知道AVPlayerViewController不再显示,因此不应该播放。

一种方法是通过在AVPlayerViewController的子视图内search相应的UIButton来在AVPlayerViewController的现有“完成”button上添加额外的动作。 findbutton后,使用addTarget添加自定义操作:action:forControlEvents:

至less这对我有用。

 - (UIButton*)findButtonOnView:(UIView*)view withText:(NSString*)text { __block UIButton *retButton = nil; [view.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if([obj isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton*)obj; if([button.titleLabel.text isEqualToString:text]) { retButton = button; *stop = YES; } } else if([obj isKindOfClass:[UIView class]]) { retButton = [self findButtonOnView:obj withText:text]; if(retButton) { *stop = YES; } } }]; return retButton; } - (void)showPlayer:(AVPlayer*)player { AVPlayerViewController *vc = [[AVPlayerViewController alloc] init]; vc.player = player; [self presentViewController:vc animated:NO completion:^{ UIButton *doneButton = [self findButtonOnView:vc.view withText:@"Done"]; [doneButton addTarget:self action:@selector(doneAction:) forControlEvents:UIControlEventTouchUpInside]; [vc.player play]; }]; } - (void)doneAction:(UIButton*)button { // perform any action required here }