20

Assume iOS 3.2 or later. What is the proper sequence of command to play a move with the controls initially hidden. When the movie is playing, the user has the option to tag on screen and show controls.

Thanks!

My (control not hidden) code:

- (void)playMovie
{
    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Test" ofType:@"m4v"]];  
    MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];  

    // Register to receive a notification when the movie has finished playing.  
    [[NSNotificationCenter defaultCenter] addObserver:self  
                                             selector:@selector(movieDone:)  
                                                 name:MPMoviePlayerPlaybackDidFinishNotification  
                                               object:moviePlayer];  

    [[NSNotificationCenter defaultCenter] addObserver:self  
                                             selector:@selector(movieState:)  
                                                 name:MPMoviePlayerNowPlayingMovieDidChangeNotification  
                                               object:moviePlayer];  

    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(movieReady:) 
                                                 name:MPMoviePlayerLoadStateDidChangeNotification 
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterFullScreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:moviePlayer];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willExitFullScreen:) name:MPMoviePlayerWillExitFullscreenNotification object:moviePlayer];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishPlayback:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];


    if ([moviePlayer respondsToSelector:@selector(setFullscreen:animated:)]) {  
        moviePlayer.controlStyle = MPMovieControlStyleDefault; // MPMovieControlStyleNone MPMovieControlStyleEmbedded MPMovieControlStyleFullscreen MPMovieControlStyleDefault
        moviePlayer.scalingMode = MPMovieScalingModeAspectFill; // MPMovieScalingModeAspectFit MPMovieScalingModeAspectFill
    }   
}

- (void) movieReady:(NSNotification*)notification 
{
    MPMoviePlayerController *moviePlayer = [notification object];  

    if ([moviePlayer loadState] != MPMovieLoadStateUnknown) {
        // Remove observer
        [[NSNotificationCenter defaultCenter] removeObserver:self  
                                                        name:MPMoviePlayerLoadStateDidChangeNotification  
                                                      object:nil];

        // When tapping movie, status bar will appear, it shows up
        // in portrait mode by default. Set orientation to landscape
        [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO];
        [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];

        // Add movie player as subview
        [[self view] addSubview:[moviePlayer view]];   

        // Play the movie
        [moviePlayer play];
        [moviePlayer setFullscreen:YES animated:YES];       
    }
}
ohho
  • 50,879
  • 75
  • 256
  • 383

3 Answers3

35

[Update] As proposed by @ReinYem, a much better solution is to rely on a MPMoviePlayerLoadStateDidChangeNotification instead of a timer.

Actually, the following solution should not be considered anymore:

Set controlStyle property to MPMovieControlStyleNone initially, and then set it to MPMovieControlStyleFullscreen one second later using a [performSelector:withObject:afterDelay:1]. It works well, controls do not appear until user taps on video.

Phil
  • 2,784
  • 2
  • 28
  • 26
  • 1
    Nice tip. I also found that if I set the control style to `MPMovieControlStyleFullscreen` immediately after calling play, it achieves the same result. So maybe there's no reason to specify an arbitrary 1 second delay? – curthipster Jun 07 '11 at 23:34
  • A one second delay worked for me as well. I tried a half second, but that was too quick. – Tod Cunningham Oct 02 '11 at 17:53
  • Yes, i too need a delay still wondering why i need to introduce such delay. – VARUN ISAC Feb 25 '14 at 07:19
34

Use a callback instead of a timer :

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hidecontrol) 
                                                 name:MPMoviePlayerLoadStateDidChangeNotification 
                                               object:playerView.moviePlayer];

With call back function :

- (void) hidecontrol {
[[NSNotificationCenter defaultCenter] removeObserver:self     name:MPMoviePlayerNowPlayingMovieDidChangeNotification object:playerView.moviePlayer];
[playerView.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];

}
ReinYem
  • 349
  • 3
  • 2
  • I really like this solution, as it covers the desired behaviour far more precisely than a timer, removing the play-but-then-pause-or-hide race condition entirely (assuming you clean up this observer in those cases too). – Rob Rix Apr 19 '12 at 15:36
  • Not only is this the "better" solution, it's the correct solution. The other simply fails in the face of unpredictable race conditions. – kevlar Jun 30 '12 at 05:43
  • 3
    Not sure this is still working on iOS 6. It seems to be random whether the loadState changes too early. Observing MPMoviePlayerPlaybackStateDidChangeNotification for a change in playbackState to MPMoviePlaybackStatePlaying seems more robust. – David Snabel-Caunt Feb 12 '13 at 18:45
  • 1
    @DavidCaunt: Your solution no longer works. On iOS 7, setting the movie controls there show them immediately. – Ricardo Sanchez-Saez Aug 05 '14 at 01:23
  • 2
    Could you explain why you remove the observer for MPMoviePlayerNowPlayingMovieDidChangeNotification? – eyuelt Aug 29 '14 at 03:36
10
player.moviePlayer.controlStyle = MPMovieControlStyleNone;

Is the newest way to do it. :)

LAMBORGHINI
  • 338
  • 2
  • 13