2015-02-23 31 views
14

我在UIViewControllerviewDidAppear方法中創建了AVPlayerViewController和附加的AVPlayer。但是,當我按下「完成」按鈕時,我的自定義視圖控制器會自動解除。如何攔截在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]; 
    } 
} 

我要求蘋果公司對這個問題,他們已經答覆如下:

感謝您的蘋果開發者技術支持聯繫(DTS )。我們的 工程師已審覈您的請求,並得出結論認爲 沒有支持的方式來實現 當前的運輸系統配置所需的功能。

回答

5

我的子類AVPlayerViewController,併發布來自viewWillDisappear的通知,指示解散AVPlayerViewController。

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

這可能不是100%正確的(因爲如果你有被顯示在AVPlayerViewController另一種觀點認爲它會失敗),但它的工作對我來說AVPlayerViewController總是在堆棧的頂部。

+0

當用戶按下完成按鈕時,我想繼續在小屏幕上播放視頻,所以我需要avplayer對象,我該怎麼辦? – 2015-08-19 12:23:37

+1

當您按完成時,AVPlayerViewController將停止播放並釋放AVPlayer。對於你所需要的,用AVPlayer創建你自己的ViewController,當用戶按下完成時,調整視圖的大小。 https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html有一個創建自己的AVPlayerViewController的例子 – dev 2015-08-19 13:18:47

+1

如果我不想子類化AVPlayerViewController(如Apple所示:不要子類AVPlayerViewController覆蓋此類的方法不受支持,並導致未定義的行爲 此處:https://developer.apple.com/library/prerelease/ios/documentation/AVFoundation/Reference/AVPlayerViewController_Class/index.html)有沒有辦法獲得通知? – 2015-08-26 09:06:46

2

你可以通過繼承AVPLayerViewController來實現。但是由於這個原因有一些不確定的行爲。 (在蘋果文檔中給出。見下文) 我也嘗試了子類化AVPlayerViewController和我面臨的內存問題。

根據蘋果的文檔:

不要繼承AVPlayerViewController。覆蓋此類的 方法不受支持,並導致未定義的行爲。

當前,它們在AVPlayerViewController關閉時不提供回調。 見蘋果開發者論壇:

在線程1蘋果小夥子說:

我仍然相信,通過利用手動管理AVPlayerViewController 實例的出口以上 推薦的手勢的方法是最可靠的方法噸Ø掌握選手視圖控制器 已經被駁回,因爲你將負責其解僱的 指向

希望它能幫助!


那麼,這個問題有一個解決辦法。您可以添加一個按鈕作爲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 2017-09-25 08:41:06

-1

一種方式是通過搜索相應的UIButton AVPlayerViewController的子視圖裏面附加的操作添加到在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繼承,因爲它不是由蘋果公司支持,可能會在未來的iOS更新的一個開拓一罐蠕蟲。

我的解決辦法是有一個定時器火災每200毫秒,檢查以下條件:

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

玩家的0 rate屬性指示視頻不再播放。如果視圖控制器被解散或已被解僱,我們可以安全地假定用戶點擊了完成按鈕。

+0

這是最安全的解決方案。 – 2017-10-25 08:43:20

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視圖控制器A,你也許可以爲您在viewDidAppear/VC viewWillAppear中A內部每當那些被稱爲,至少我們知道,AVPlayerViewController不再顯示,從而不應該玩。

1

我解決了保持對AVPlayerViewController實例的弱引用,並使用定時器進行監視,其中引用更改爲nil。

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