1

サブビューでビデオを再生する2つのクロスフェードビューコントローラーがあります。ビュー A のビデオは、フェードインの開始時に再生を開始し、フェードアウトの終了時に停止します。ビュー B のビデオは、フェードインで開始し、フェードアウト後に停止します。基本的なもの。MPMoviePlayerController で正常に動作するようにしましたが、オーディオのフェードイン/アウトも実行したかったため、AVFoundationFramework の AVPlayer を使用する必要がありました。基本的にはすべて問題なく動作しているように見えましたが、スイッチが原因でフェードインが壊れていることに気付きました。ビュー B アルファは 0 から 1 にジャンプするだけで、UIView animateWithDuration の完了ブロックが false 値で呼び出されます。これは、loadView メソッド中に AVPlayer オブジェクトの replaceCurrentItemWithPlayerItem: メソッドを呼び出した場合にのみ発生することに気付きました。

クロスフェード コードは次のようになります。

- (void)pushViewController:(UIViewController *)viewController duration:(float)duration
{    
    float halfFadeInOutTime = duration/2.0;
    viewController.view.alpha = 0.0;
    UIView *tmpView = self.view;


    [viewController viewWillAppear:YES];

    //start fading out the first view
    [UIView animateWithDuration:halfFadeInOutTime 
                          delay:0 
                        options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
                     animations:^{
                         tmpView.alpha = 0.0;
                     } 
                     completion:^(BOOL finished){
                         if( finished ){
                             if( [self respondsToSelector:@selector(fadeOutFinished:)] ){
                                 [self fadeOutFinished:duration];
                             }


                             [self.navigationController pushViewController:viewController animated:NO];

                             //start fading in with the second view
                             [UIView animateWithDuration:halfFadeInOutTime 
                                                   delay:0
                                                 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
                                              animations:^{
                                                  viewController.view.alpha = 1.0;
                                              } 
                                              completion:^(BOOL finished2){
                                                  if( finished2 ){
                                                      if( [((CrossfadeableViewController*)viewController) respondsToSelector:@selector(fadeInFinished:)] ){
                                                          [((CrossfadeableViewController*)viewController) fadeInFinished:duration];
                                                      }
                                                  }
                                              }
                              ];

                             if( [((CrossfadeableViewController*)viewController) respondsToSelector:@selector(fadeInStarted:)] ){
                                 [((CrossfadeableViewController*)viewController) fadeInStarted:duration];
                             }


                         }
                     }
     ];

    if( [self respondsToSelector:@selector(fadeOutStarted:)] ){
        [self fadeOutStarted:duration];
    }
}

loadView の AVPlayer 関連のコードは次のようになります

- (void) loadView
{
    [super loadView]

    //...

    /* 
     * Variables of type:
     * UIView *videoPlaceholder;
     * AVURLAsset *asset;
     * AVPlayerItem *playerItem;
     * AVPlayer *player;
     * AVPlayerLayer *playerLayer;
     */ 

    videoPlaceholder = [[UIView alloc] initWithFrame:_frame];

    playerLayer = [[AVPlayerLayer alloc] init];
    [playerLayer setFrame:videoPlaceholder.frame];
    playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    player = [[AVPlayer alloc] init];

    NSString *_url = [[NSBundle mainBundle] pathForResource:[_videoFilename stringByDeletingPathExtension] ofType:[_videoFilename pathExtension]];
    if( _url != nil ){
        NSURL *url = [NSURL fileURLWithPath:_url];

        asset = [AVURLAsset URLAssetWithURL:url options:nil];

        playerItem = [AVPlayerItem playerItemWithAsset:asset];

        [player replaceCurrentItemWithPlayerItem:playerItem];
        [player seekToTime:kCMTimeZero];
        [player setActionAtItemEnd:AVPlayerActionAtItemEndNone];
    }



    playerLayer.player = player;
    [videoPlaceholder.layer addSublayer:playerLayer];

    [self.view addSubview:videoPlaceholder];

    //....
}

アニメーションが壊れる原因を知っている人はいますか? クロスフェードが開始する前に loadView が呼び出されるため、アニエーション中にビューで何も変更していません。また、同じコードが MPMoviePlayerController で機能し、AVPlayer で壊れる原因は何ですか?

乾杯、PB

4

1 に答える 1

3

結局のところ、AVPlayerItem が読み込まれていることが問題でした。ムービーが読み込まれるまで待たなければなりませんでした。そうしないと、アニメーションのフェードインが壊れてしまいました

動画の読み込みが完了するまで待機するサンプル コード:

- (void)observeValueForKeyPath:(NSString*) path 
                  ofObject:(id)object 
                    change:(NSDictionary*)change 
                   context:(void*)context {
  if (context == AVPlayerDemoPlaybackViewControllerStatusObservationContext) {
      AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
      if (status == AVPlayerStatusReadyToPlay) {
        if( [self.videoStateChangeDelegate respondsToSelector:@selector(videoStateChangedToReadyForPlayback)] ){
            [self.videoStateChangeDelegate videoStateChangedToReadyForPlayback];
        }
        [self.player play];
      }
  }
}

ここで [self.videoStateChangeDelegate videoStateChangedToReadyForPlayback] は、デリゲート コントローラーにフェードインを開始できることを通知します。この問題により、単純なコードが少し複雑になったのは残念です。

于 2012-08-15T09:56:48.093 に答える