Delay between play button and movie showing - iphone

I have a simple view that creates a MPMoviePlayerViewController when the user presses a button, using the presentMoviePlayerViewControllerAnimated: method. The new view controller slides in and shows the movie player, so far so good.
However, when the button is pushed, the current view controller slides out the bottom, showing a ugly (probably default) white view, that sticks around anywhere from half a second to a few seconds, until the movie view controller is shown. It seems like it's dependent on my network connection, as if the movie view controller is downloading parts of the movie before showing the player.
Am I doing something wrong, or how can I work around this? I'd really prefer to just show the movie view controller directly, maybe even without sliding out the previous view controller that holds the play button, but still animated like a modal view controller.
Thanks!
Christoph

The solution was to init the player view controller when the parent view is created, and then call prepareToPlay on the moviePlayer inside it. That removes the latency when the play button is pushed and (I guess) moves it to when the user gets to the parent view from which he can play the movie.
EDIT:
This removes the delay, but for some reason, initializing the movie view controller also autoplays it when it's loaded, so that's not a good solution.

I ended up just setting the background of the view to black. Doesn't fix the delay, but makes it look much nicer:
theMovieVC.view.backgroundColor = [UIColor blackColor];

this is what i do for iOS > 3.2 :
- (void) play {
mMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:mMovieURL];
if ([mMoviePlayer respondsToSelector:#selector(loadState)])
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePreloadDidFinishIOS32:)
name:MPMoviePlayerContentPreloadDidFinishNotification
object:nil];
[mMoviePlayer prepareToPlay];
[mMoviePlayer play];
mMoviePlayer.controlStyle = MPMovieControlStyleEmbedded;
[mMoviePlayer setMovieControlMode:MPMovieControlModeDefault];
[mMoviePlayer setBackgroundColor:[UIColor clearColor]];
}
}
and
- (void) moviePreloadDidFinishIOS32:(NSNotification*)notification;
{
// Remove observer
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerContentPreloadDidFinishNotification
object:nil];
self.view = mMoviePlayer.view;
}
Thus in the viewdidload you can instantiate what you want (UIActivityIndicatorView for example). The view controller will only be replaced when the preload is finished.

I'm noticing the same issue in my app. Anyone have suggestions to avoid this issue?
In my case, I'm pushing the MPMoviePlayerViewController to the UI as a modal popup.
// build the movie player
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
MPMoviePlayerViewController *movieViewController = [[[MPMoviePlayerViewController alloc] initWithContentURL:request.URL] autorelease];
[movieViewController.moviePlayer prepareToPlay];
movieViewController.view.backgroundColor = [UIColor blackColor];
// show the movie player view
[self.parentViewController presentModalViewController:movieViewController animated:YES];

Related

playing youtube video inside uiwebview. How to handle the "done" button?

I have a uiwebview that plays a youtube video. How can I handle the done button action?
Right now, when I tap the done button it changes back to my app main menu (not the menu that was supposed to dismiss to) and it just freezes. Can anyone help me please?
Ps: the menu where the uiwebview is located, was previously presented modally.
The YouTube plug-in player is itself a modal view controller. It is returning to its presentingViewController when the done button is pressed. Its presentingViewController is not your modal view controller but is instead the viewController that called [presentModalViewController:animated:] to present your modal view controller. Since the original modal view controller is still active, the app behaves badly.
To fix the problem,
1) Track whether the modal view controller has been presented but not dismissed.
2) In the viewDidAppear method of the presenting view controller, if the modal view controller was presented and not dismissed, dismiss and present it again.
For example, in controller that is presenting the modal web view controller:
- (void) presentModalWebViewController:(BOOL) animated {
// Create webViewController here.
[self presentModalViewController:webViewController animated:animated];
self.modalWebViewPresented = YES;
}
- (void) dismissModalWebViewController:(BOOL) animated {
self.modalWebViewPresented = NO;
[self dismissModalViewControllerAnimated:animated];
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.modalWebViewPresented) {
// Note: iOS thinks the previous modal view controller is displayed.
// It must be dismissed first before a new one can be displayed.
// No animation is needed as the YouTube plugin already provides some.
[self dismissModalWebViewController:NO];
[self presentModalWebViewController:NO];
}
}
This thread is very useful and help me to find the problem!
The answer of lambmj works fine, but I found a better way.
In presenting view controller:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.presentedViewController) {
UIViewController *vc = self.presentedViewController;
[vc dismissModalViewControllerAnimated:NO];
[self presentModalViewController:vc
animated:NO];
}
}
Hope this helps!
#Gdx Wu
#lambmj
Thanks for your methods, they work fine. But there is some small problem that after clicking the done button & jumping directly to the presenting view controller, we need to dismiss the presented modal view controller and present it again, which would bring some dither(like flash) between these view controller switches.
Based on this, I highly recommend #IsaacCisneros 's method which would switch seamlessly.
Simply remove UIWebView when it enters full screen; add back UIWebView when it exit full screen. Sample code below assuming a UIViewController with subview of UIWebView, and your UIWebView should have youtube iframe.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Add observer for "Done" button click
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerWillExitFullscreen:)
name:#"UIMoviePlayerControllerWillExitFullscreenNotification"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerDidEnterFullscreen:)
name:#"UIMoviePlayerControllerDidEnterFullscreenNotification"
object:nil];
}
- (void)viewDidDisappear:(BOOL)animated {
// Remove observers for "Done" button click
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UIMoviePlayerControllerWillExitFullscreenNotification" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
}
- (void)playerWillExitFullscreen:(NSNotification *)notification {
// Before exit full screen, add back UIWebView that have been removed earlier
[self.view addSubview:self.webView];
}
- (void)playerDidEnterFullscreen:(NSNotification *)notification {
if (self.presentingViewController) { // UIWebView is presenting the build-in movie player controller
[self.webView removeFromSuperview]; // Built-in movie player controller is already entering full screen mode
}
}

MPMoviePlayerViewController called from UITabBarController doesn't send notifications in IOS5

I had an app that worked fine in IOS4 but stopped displaying videos in IOS5. Previously I was using MPMoviePlayerController, so I switched to MPMoviePlayerViewController and now the videos display fine in IOS5.
But, now in IOS5, when the Done button is pressed the video stops playing in MPMoviePlayerViewController, but the MPMoviePlayerController no longer calls Notifications.
The hierarchy looks like:
AppDelegate -> UITabBarController -> UITableView -> UIViewController within which the MPMoviePlayerViewController is called. Inside the UIViewController the code looks like:
MPMoviePlayerViewController *tmpMoviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:movieURL];
self.moviePlayer = tmpMoviePlayer;
[self presentMoviePlayerViewControllerAnimated:self.moviePlayer];
NSNotificationCenter *notificationCenter = [ NSNotificationCenter defaultCenter ];
[notificationCenter addObserver:self
selector:#selector(moviePlayerPlaybackDidFinish:)
name:MPMoviePlayerWillExitFullscreenNotification
object:[self.moviePlayer moviePlayer ]];
I've also tried the following notification names and none of them get triggered:
MPMoviePlayerPlaybackDidFinishNotification
MPMoviePlayerPlaybackStateDidChangeNotification
MPMoviePlayerPlaybackDidFinishReasonUserInfoKey
MPMoviePlayerNowPlayingMovieDidChangeNotification
MPMoviePlayerWillExitFullscreenNotification
MPMoviePlayerDidExitFullscreenNotification
I have seen a SO posting where the MPMoviePlayerViewController was called from within a UITabBarController and the view that called presentMoviePlayerViewControllerAnimated wasn't selected correctly, but I haven't been able to get any other view to work for calling presentMoviePlayerViewControllerAnimated.
Any ideas why the notifications are no longer called when the Done button of MPMoviePlayerViewController is pressed?
I did solve this but I can't remember what the fix actually was. But I can show the code that works now:
[ notificationCenter addObserver: self
selector:#selector(moviePlayerPlaybackDidFinish:)
name: MPMoviePlayerPlaybackDidFinishNotification
object: moviePlayer ];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
self.moviePlayer.shouldAutoplay = NO;
[self.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[[self view] addSubview:[self.moviePlayer view]];
[self.moviePlayer setFullscreen:YES animated:YES];
[self.moviePlayer play];

Why is the title bar appearing behind the status bar after a rotation?

I have a UIViewController whose view is a UIWebView with an embedded movie. When the movie is playing full screen, and the device is rotated, the title bar ends up behind the status bar after the movie is dismissed. Why might this happen?
Turns out that the animation of the view controller's view wasn't finished when the video started. This caused it to be redisplayed over the video player view.
My solution:
(void)viewDidLoad
{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:NO];
[UIApplication sharedApplication].keyWindow.frame=CGRectMake(0, 20, 320, 460);
self.navigationController.navigationBar.hidden=NO;
}
did you autoresizingMask on the UIWebView
webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth);
and
-(BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) orientation
{
return YES;
}
It's no way to resolve this problem using MPMoviePlayerNotification, because UIWebView Video Don't use MPMoviePlayerViewController or it's private for developer.
But, there's another way to fix this bug.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleStatusBarFrameDidChange)
name:UIApplicationDidChangeStatusBarFrameNotification
object:nil];
- (void)handleStatusBarFrameDidChange {
self.navigationController.navigationBarHidden = YES;
self.navigationController.navigationBarHidden = NO;
}

iPhone SDK: handling keybaord appearance

I need to move UI elements of my view controller when keyboard appears. I do this by registering for the keyboard notifications in my app delegate:
[[NSNotificationCenter defaultCenter] addObserver:observer
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:observer
selector:#selector(keyboardWasHidden:)
name:UIKeyboardDidHideNotification object:nil];
and then handling notification as prescribed by Apple (I have similar code for keyboard was shown) to scroll the view up and down:
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
CGRect viewFrame = [self.view frame];
viewFrame.origin.y += keyboardSize.height - TOOLBAR_HEIGHT;
self.view.frame = viewFrame;
}
So far so good. Now problem description:
When I execute this code to show OS 3.0 specific message UI:
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[self presentModalViewController:picker animated:YES];
and when keyboard shows in the actual mail UI, I still get keyboard notification which scrolls my view and therefore breaking my UI (note that mail controller takes entire screen and my view is not even visible at this point).
I was hoping to temporary disable keyboard notification, so my scrolling code would not get called with this line:
[[NSNotificationCenter defaultCenter] removeObserver:self];
But it does not help, keyboard even still get posted.
What should I do avoid reacting on the keyboard when it created by the message UI?
Add a BOOL property or instance variable: careAboutKeyboard that's accessible to both your keyboardWasShown: and keywardWasHidden: methods, likely in the view controller those methods are in.
Have it set to YES when in the viewWillAppear method, and set to NO when you show the mail view and in viewWillDisappear.
Then put all of your scrolling logic in an if block:
if(careAboutKeyboard) {
// Scrolling logic
}

Activity indicator in a UITabBar application on the iPhone

I have a UITabBar + UINavigationController application which often needs data from the internet. Sometimes it takes quite a while before it gets it, so I would like to show an activity indicator.
What I was trying is to add a activityView to my window in my applicationDidFinishLaunching method:
[window addSubview:tabBarController.view];
fullscreenLoadingView.hidden = YES;
[window addSubview:fullscreenLoadingView];
And then I add the application delegate as a observer to the default notification center:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(startFullscreenLoading:) name:#"startFullscreenLoading" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(stopFullscreenLoading:) name:#"stopFullscreenLoading" object:nil];
and implement the methods:
- (void)startFullscreenLoading:(NSNotification *)notification {
fullscreenLoadingView.hidden = NO;
}
- (void)stopFullscreenLoading:(NSNotification *)notification {
fullscreenLoadingView.hidden = YES;
}
When I then use this directly in the applicationDidFinishLaunching method the loading indicator view shows upp as expected:
[[NSNotificationCenter defaultCenter] postNotificationName:#"startFullscreenLoading" object:self];
But when I use it from one of the navigation controllers the startFullscreenLoading: method is called but I don't see the loading indicator view. Why is that?
Are you loading your data on a background thread? Your main thread will be blocked & won't be able to redraw or process any other events.
The most likely thing I can guess is that your indicator view is below some other view. Try
[[fullScreenLoadingView superView] bringSubviewToFront:fullScreenLoadingView]
If that doesn't work, I would suggest breaking inside of -startFullscreenLoading to make sure the fullscreenLoadingView is still valid.
In my app I did this by adding the UIActivityView in IB and making sure it was above everything else (as a top-level object). It's set to be invisible when stopped.
Then in my code I make it appear with [activityIndicator startAnimating] and make it disappear with [activityIndicator stopAnimating];