Currently my -[MPMoviePlayerController backgroundView] does not appear until movie loaded enough. So UIActivityIndicatorView which I placed on there does not appear immediately. This drives me crazy. The only solution have been found is placing duplicated indicator-view somewhere between background-view and -[MPMoviePlayerController view]. But this does not look regular, and definitely a view hierarchy hack which is not guaranteed to work properly. If the background-view shows immediately, all will work magically.
How can I make the background-view immediately before movie loaded?
Do not use the backgroundView but the view of the moviecontroller itself...
Following steps (assuming your MPMovieControllerPlayer instance is called moviePlayerController and your UIActivityIndicatorView instance is called activityIndicatorView)
Add your UIActivityIndicatorView on top of the MPMoviePlayerController view (e.g. [moviePlayerController.view addSubview:activityIndixatorView];)
Start animating the activity indicator
Register for MPMoviePlayerLoadStateDidChangeNotification
Within the handler of the above notification, watch out for moviePlayerController.loadState & MPMovieLoadStatePlayable == MPMovieLoadStatePlayable
If the above condition is matched, hide your activity indicator
I am not sure but Can a UIActivityIndicator be displayed over a MPMoviePlayerController in full screen mode? may help you a bit
Related
I have a very basic screen sharing iPhone app, I have successfully added the pinch/zoom effect to my app using a UIImageView inside a UIScrollView.
The UIImageView receives the screen content from the PC on a regular interval. Everything works fine but as soon as I scroll/pinch/zoom it works at first but then it stops, and the delegate method that's updating the image view content stops firing up even though the server still sends the screen content. The whole app seems to be frozen but there are no error messages/exceptions/whatever. Can anyone help me, please?
If you are using NSDefaultRunLoopMode, UIAPPlication adds a run loop mode UITrackingRunLoopMode for tracking scrollview events like scrolling. Since the UIApplication switches from NSDefaultRunLoopMode to UITrackingRunLoopMode any events on NSDefaultRunLoopMode will not be called until UIAPPlication switch back to NSDefaultRunLoopMode.
It might be the problem, the fix is change NSDefaultRunLoopMode to NSRunLoopCommonModes .
If you are not sure whether you are using runloop or not as you mentioned in comment. Just search NSDefaultRunLoopMode in your project.
I'm trying to display the content of the camera in a custom view. What I just want to achieve is to have custom buttons to take pictures in order to take more than one photo at a single time.
It should work out of the box, theoretically, but in practice sometimes it happens that if I dismiss my custom view controller and then I re-open it "quickly", the UIImagePickerController just shows a blank (black, actually) content. The funny thing is that if you try to take a picture, the camera actually is enabled and the shutter opens and you can collect the image. The only issue seems to be related to displaying the live-content into a specific UIView.
This is the code I use for displaying it:
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
[imagePickerController setSourceType:UIImagePickerControllerSourceTypeCamera];
[imagePickerController setShowsCameraControls:NO];
[imagePickerController setEditing:NO];
[imagePickerController setNavigationBarHidden:YES];
[imagePickerView addSubview:[imagePickerController view]];
[imagePickerController viewWillAppear:YES];
I don't like that viewWillAppear method call but it is the only way I found in order to show it.
imagePickerView is, indeed, the view that I have previously created to place the picker into.
By digging a little bit the problem myself, I noticed that if I wait a couple of seconds before re-opening my custom view controller, the picker shows up normally.
By taking a look into the console it seems that the picker (or the camera resource associated to it) is actually released after a while but this is just a guess.
Any clue? Thanks
You definitely need that viewWillAppear call, and likely more. Whenever a UIImagePickerController is presented by one of the "indirect" presentation methods (like a modal presentation, or being pushed on a navigation stack), it's automatically sent all of the appropriate display related notifications: viewWillAppear:, viewDidAppear:, viewWillDisappear:, and viewDidDisappear:.
Internally UIImagePickerController uses these notifications to take appropriate initialization actions, like the shutter effect. You don't know how it uses them, you just have to be sure it gets them.
When you present the UIImagePickerController directly by adding it's view as a subview, you deprive it of automatically receiving these notifications. From the View Controller Programming Guide:
If you incorporate a view
controller’s view into your hierarchy
by other means (by adding it as a
subview to some other view perhaps),
the system assumes you want to manage
the view yourself and does not send
messages to the associated view
controller object.
This isn't necessarily bad, it just means you need to shoulder the responsibility for those messages yourself. I haven't seen this exact issue that you're having with display of the picker, but my first attempt at a fix would be to ensure that each of those 4 display related notifications are sent to the picker controller at the appropriate time, especially the disappearing ones, if you aren't already doing so.
I've built an app that uses a UITableView inside a UINavigationController, inside a UITabBarController. Every entry in the UITableView opens up a view that contains some basic text, buttons, but most importantly, an MPMoviePlayerController that plays audio when started. A user can click this MPMoviePlayerController and continue to browse around the rest of the app (different tabs, or moving back in the navcontroller, opening other views from the tableview) and continue to hear the audio.
I'd like the user to be able to return to the view with the active MPMoviePlayerController at any time. I understand how I would go about allowing the user to return to a certain view from any view, but I'm struggling with how to prevent that view from being reloaded when the user tries accessing the same view.
Is there any way I can save a view in memory? Or save the active MPMoviePlayerController as some type of global object, so that I can at least access that from anywhere?
I appreciate any and all help. Thanks!
I'd recommend you create a property for the MPMoviePlayerController in your app's UIApplicationDelegate (which you can then access from anywhere in the code with [UIApplication sharedApplication].delegate but you will need to cast to your UIApplicationDelegate subclass).
When you come to enter the screen which plays content, check whether your movie player property in the app delegate is nil, if it is create it, otherwise re-use it.
Don't forget to release the reference to your MPMoviePlayerController when the media stops playing, or when the media has already stopped and you get a memory warning or when your app shuts down.
The down side of this approach is it causes coupling between most of your view controllers and your app delegate. You could mitigate this with the use of a protocol however.
You should simply retain it. Like this [myView retain] and keep a pointer to it in where you need. When you want myView to appear, just add it as a subview to current visible view like[myController.view addSubview:myView].
Hope that will help, Good luck!
I've found that even adding a retain doesn't do the trick. I've actually found the best success with overriding the setView (since part of unloading the view involves calling setView:nil. I have a BOOL that gets set the FIRST time the VC loads and once thats set it will never allow setView to be called again.
- (void) setView: (UIView*) view{
NSLog(#"MainViewController: setView");
// this is our attempt to stop iOS from unloading our view.. when iOS tries to unload your view they call setView:nil.. so, no!
if(!viewDidAppear) [super setView:view];
}
A little bit of a hack, but you can override setView: in your subclass so that it never allows to set the view to nil:
-(void)setView:(UIView *)view
{
if (view == nil) return;
[super setView:view];
}
Ok, so here's the thing. I have a UIViewController that contains a UITabBarController. That tab bar has a UIViewController for each tab button. Now, inside one of the tab buttons is an MPMoviePlayerController that is playing a stream from over the network. Playing the stream works just fine and you can see the video and hear the audio.
The problem is when you navigate to another tab. The audio still plays, which is good, but when you go back to the stream, the video is black. The audio is still playing, but the video needs to be playing too.
Has anyone run into this problem before?
I'm currently using iOS 4.0 to build against and an iPhone 3GS.
If more information is needed, just ask and I'll do my best to answer.
Thanks,
Robbie
Strange things might happen if the view isn't on-screen (I believe it's removed from the view hierarchy when you switch tabs).
Have you tried using MPMoviePlayer's view directly? (not MPMoviePlayerController)
Can you add and remove the view and keep the movie playing?
Does pausing and resuming help?
Could you pass the view around between view controllers, or maybe make it a direct subview of the window in viewWillDisappear and move it back in viewDidAppear? (I'm not sure if the view's been removed from the hierarchy in viewWillAppear/viewDidDisappear.)
The solution I'm going ahead with is entering fullscreen mode and exiting fullscreen mode very quickly. It may not be the best thing, but it's working.
This still happens on iOS 6. If I have two movie player (one on each tab), even if they are not playing, if I switch form the first to the seconds tab and return to the first, the movie player will be black.
My solution was as simple as calling prepareToPlay on -viewDidAppear::
- (void)viewDidAppear:(BOOL)animated;
{
[super viewDidAppear:animated];
[self.moviePlayer prepareToPlay];
}
I believe this will add the shared internal view of MPMoviePlayerController to the view hierarchy.
I am using the UIWebView to load both streaming audio and video. I have properly set up the UIWebView delegate and I am receiving webViewDidStartLoading and webViewFinishedLoading events perfectly. The webview launches a full screen window (likely a MPMoviePlayerController)
Apple's MoviePlayer example gets the array of Windows to determine which window the moviePlayerWindow is for adding custom drawing/getting at the GUI components. I believe this to be a bad practice/hack.
My expectation is that I should be able to figure out when that button was clicked by either a delegate method or an NSNotification. It may also be the case that I have to poke around subviews or controllers with isKindOf calls, but I don't think those are correct approaches.
Are my expectations incorrect, and if so, why?
What is the correct way to bind an action to that "Done" button?
There isn't an MPMoviePlayer instance method that covers this. You can use - (void) moviePlayBackDidFinish:(NSNotification*)notification to find out when the movie has finished. Or you could overlay the existing Done button with your own and have complete control that way.
You can also use MPMoviePlayerWillExitFullscreenNotification in order to conrol the action provided that youe MoviePlayer is in fulscreen mode.