Overlay UIView on MPMoviePlayerController

So you wanna overlay a UIView on MPMoviePlayerController?

Tried


[self.view addSubView:myView];

to no avail, right? The reason that fails is that MPMoviePlayerController actually creates a new window and overlays that on your app. This means you can’t just add a subview — it’ll just be hidden.

Try this oversimplified example:


MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:myURL]];

[[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(playerFinishedPlaying:)
name:MPMoviePlayerPlaybackDidFinishNotification object:player];

[player play];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = @"Hi, I'm on your MPMoviePlayerController";
label.transform = CGAffineTransformMakeRotation(M_PI/2.0);
label.frame = CGRectMake(0,0,20,480);

[[[UIApplication sharedApplication] keyWindow] addSubview:label];

Wait, WTF? Clever folks might have tried [player _window], which works great on the simulator but fails to build for the device. The trick here is that the sharedApplication’s keyWindow IS the player’s window once the player is on screen, so adding a subview to that window overlays said view on the player. I did run into a bug where the keyWindow property was nil after the player was shown, so if you want to use that again later, make sure to call:


[self.view.window makeKeyAndVisible];

when the player calls back on your controller handling MPMoviePlayerPlaybackDidFinishNotification (in this case, playerFinishedPlaying:).

UPDATE: For iPhone 3.0, I can only get this to work with a bit of a hack — use a timer to show the overlay later. >.< Not sure I like this approach or think it’s reliable but it seems to work. Test it and YMMV for sure.


...

[player play];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(showOverlay:) userInfo:nil repeats:NO];
}

- (void)showOverlay:(NSTimer *)timer {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = @"Hi, I'm on your MPMoviePlayerController";
label.transform = CGAffineTransformMakeRotation(M_PI/2.0);
[label setBackgroundColor:[UIColor redColor]];
label.frame = CGRectMake(0,0,20,480);

NSArray *windows = [[UIApplication sharedApplication] windows];
UIWindow *mpw = [windows objectAtIndex:1];
[mpw addSubview:label];
}

6 Responses to “Overlay UIView on MPMoviePlayerController”


  • wow cool :) thax for the post

  • Good post! If instead a Label I insert a UIImageView, how do I detect a touch to that view. I am trying it here and TouchesBegan receives no event… if you know the answer and post here the answer, please drop a note to my email to let me know… thanks.

  • I think one of the apple sample apps does this. MovePlayer, maybe?

  • Can you give me your sample code. I want try it. But I can’t see it on my simulator. Please help me. Thank you.

  • I am desperately trying to find a way to get the currentTime from the MPMoviePlayerController. setInitialPlaybackTime works as expected so does setCurrentTime (undocumented), however the undocumented currentTime method seems to return junk. Does anyone have any idea how to get the current time of the slider/scrubber. This is a function that every Media Framework provides. Am I missing something? I would settle for getting the slider itself if there is a way and try and get its current value. It must have the correct values.

  • What I do for 3.0+ is listen for a key window change notification (which the MPMoviePlayerController will make himself the key window and create a new UIWindow instance).

    Make sure you add this code before calling play.


    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyWindowChanged:)
    name:UIWindowDidBecomeKeyNotification
    object:nil];

    Then in your handleKeyWindowChanged event you can get the UIWindow instance that is the movie player:


    -(void)handleKeyWindowChanged:(NSNotification*)note
    {
    UIWindow *window = [note object];
    }

    And add subviews like above. I actually keep a flag when I start playing and when the play back ends and check to make sure I’m playing before doing anything in the above event.

Leave a Reply

You must login to post a comment.