2015-02-23 3 views
14

Я создал AVPlayerViewController и прилагается AVPlayer в способе viewDidAppear пользовательского UIViewController. Однако, когда я нажимаю кнопку «Готово», мой пользовательский контроллер просмотра автоматически отбрасывается.Как перехватить нажатие сделанной кнопки в AVPlayerViewController?

Я хотел бы перехватить это действие, чтобы использовать мой собственный сеанс Segue, но я не уверен, как это сделать. Я нашел примеры для MPMoviePlayerViewController, но не AVPlayerViewController.

код я нашел для MPMoviePlayerViewController ниже:

- (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, об этой проблеме, и они ответили следующим образом:

Благодарим Вас за обращение в компании Apple Developer Technical Support (DTS). Наши инженеры рассмотрели ваш запрос и пришли к выводу, что существует нет поддерживаемого способа достижения желаемой функциональности, учитывая в настоящее время.

ответ

5

Я подклассифицировал AVPlayerViewController и отправляю уведомление из viewWillDisappear, чтобы указать отклонение AVPlayerViewController.

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

Это может быть не 100% правильно (как это было бы ошибкой, если у вас есть другое мнение, что отображается над AVPlayerViewController), но он работал для меня, как AVPlayerViewController всегда на вершине стека.

+0

Когда пользователь нажимает кнопку «Готово», я хочу продолжить воспроизведение видео на маленьком экране, поэтому мне нужен объект avplayer, что мне делать? –

+1

AVPlayerViewController останавливает воспроизведение и отпускание AVPlayer при нажатии. Для чего вам нужно создать свой собственный ViewController с AVPlayer в нем, а когда пользователь нажмет, просто измените размер представления. https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html имеет пример создания вашего собственного AVPlayerViewController – dev

+1

В случае, если я не хочу подклассифицировать AVPlayerViewController (как предлагает Apple: Do not subclass AVPlayerViewController. Переопределение методов этого класса неподдерживается и приводит к неопределенному поведению. здесь: https://developer.apple.com/library/prerelease/ios/documentation/AVFoundation/Reference/AVPlayerViewController_Class/index.html) есть ли способ получить уведомление? –

2

Вы можете сделать это путем подкласса AVPLayerViewController. Из-за этого существует некоторое неопределенное поведение. (Дано в документах Apple. См. Ниже) Я также попытался подклассифицировать AVPlayerViewController, и я столкнулся с проблемой памяти.

Согласно Apple, Docs:

Не подкласс AVPlayerViewController. Переопределение методов этого класса не поддерживается и приводит к неопределенному поведению.

В настоящее время они не предлагают обратный вызов при отклонении AVPlayerViewController. См форум Apple, разработчик:

В thread1 Apple, парень говорит:

Я до сих пор считаю, что управление выходом экземпляра AVPlayerViewController вручную, используя рекомендуемый метод жестов выше был бы самым надежным способом t О знаем, что контроллер представления игрока был уволен, так как вы будете нести ответственность за его увольнение в , что точка

Надеется, что это помогает!


У вас есть проблема. Вы можете добавить кнопку в качестве подзапроса AVPlayerViewController. Таким образом, вы можете перехватить жест нажатой кнопки.

0

Поскольку здесь нет идеальных ответов, обходной путь, который вы можете использовать для некоторых ситуаций, заключается в том, чтобы отслеживать, продолжает ли AVPlayer, и устанавливать наблюдателя на случай, если он автоматически закрывается после того, как он будет воспроизведен полностью ,

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 
    //******* 
    } 
+0

Что делать, если пользователь приостанавливает видео? Это считается остановкой? – Jonny

-1

Один из способов, чтобы добавить дополнительные действия для кнопки существующего «Done» на AVPlayerViewController путем поиска соответствующего UIButton внутри подвидов в AVPlayerViewController. После того, как кнопка найдена, добавьте пользовательское действие с помощью addTarget: действие: forControlEvents:

По крайней мере, это работает для меня.

- (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 
} 
4

Тот факт, что Apple не обеспечивает встроенный способ обработки кнопки «Готово», разочаровывает.

Я не чувствовал себя наследованием от AVPlayerViewController, потому что он не поддерживается Apple и, вероятно, откроет банку червей в одном из следующих обновлений iOS.

Мой обходной путь, чтобы иметь пожара по таймеру Через каждые 200 мс и проверьте следующее условие:

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

rate собственности игрока 0 указывает, что видео больше не играет. И если диспетчер представлений отклоняется или уже уволен, мы можем с уверенностью предположить, что пользователь нажал кнопку «Готово».

+0

Это самое безопасное решение imo. –

0

Вот код, которому удалось обнаружить клики.

В классе делегатов приложения. Но он обнаруживает, что каждая кнопка находит в этом виде. Вы можете добавить некоторый контроль, проверить заголовок что-то вроде этого.

-(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"); 
} 
0

Если у вас есть вид контроллера, который представляет AVPlayerViewController, вы, вероятно, может проверить в viewDidAppear/viewWillAppear внутри VC А. Всякий раз, когда их называют, по крайней мере, мы не знали бы, что AVPlayerViewController больше не показывается и, таким образом, не должен играть.

1

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

private weak var _playerViewController : AVPlayerViewController? // global reference 
    ... 
    ... 
    let playerController = AVPlayerViewController() // local reference 
    ... 
    self.present(playerController, animated: true) { [weak self] in 
     playerController.player?.play() 
     self?._playerViewController = playerController 
     // schedule a timer to intercept player dismissal 
     Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] (timer) in 
     if self?.playerViewController == nil { 
      // player vc dismissed 
      timer.invalidate() 
     } 
} 
Смежные вопросы