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.
Related
In my Universal App I have a long UITableView with custom cells..and for some cells I may need to show some long pop-up explanaiton about that cell when for instance user clicks a "i" label on the cell. In iPad popover view seems excellent choice for this, but don't know how can I implement this on iPhone, what are the possibilities? Also I want to spend as less time as possible when making it work for iPad- popover view. I want to re-use some of the code or logic i use on iPhone
Things came up to my mind;
-Show explaination in alert shild, but the current look and feel of alert shield is ugly can I customize it however I like and show wherever I line on screen and if I can make it scrollable;
-Or maybe I can make a uitextview to show on top, but then how will I dismiss it, I will need some buttons there..which sounds tricky.
-UIActionsheet with a uitextview on it, is reasonable here?
Also I found this code in S.O but dont know how to use this in my case;
newView.frame = CGRectMake(60, 140, 200, 200);
[parentView addSubview:newView];
Have a look at http://iosdevelopertips.com/open-source/ios-open-source-popover-api-for-iphone-wepopover.html. It's a Popover component for iPhone. I think it works best in your case. You can Google "iphone popover" for more options.
We built an open source library for iPad-like popovers on iPhone allowing you to customise the look and feel of the popovers and place any view or controller inside it.
Watch the project on Github and download it at http://www.50pixels.com/blog/labs/open-library-fppopover-ipad-like-popovers-for-iphone/
On dismissing it, see the following instructions:
Know when a new popover is displayed
- (void)presentedNewPopoverController:(FPPopoverController *)newPopoverController
shouldDismissVisiblePopover:(FPPopoverController*)visiblePopoverController;
Use this delegate method to know when a new different popover is displayed. If you want to dismiss the old popover, and release it, send the dismiss message inside this method.
- (void)presentedNewPopoverController:(FPPopoverController *)newPopoverController
shouldDismissVisiblePopover:(FPPopoverController*)visiblePopoverController
{
[visiblePopoverController dismissPopoverAnimated:YES];
[visiblePopoverController autorelease];
}
Know when the popover is dismissed
- (void)popoverControllerDidDismissPopover:(FPPopoverController *)popoverController;
Use this delegate method to know when the popover is dismissed. This could happen when the user taps outside the popover or when a dismiss message is sent by other actions.
Typically if you used a UIPopover on the iPad you use present a Modal view controller on the iPhone.
So if you create a subclass of UIViewController (e.g. called MyViewController), with the necessary subviews such as a UILabel.
MyViewController *infoViewController = [[MyViewController alloc] init];
//pass data to the new view controller, e.g.
//[infoViewController setInfoText:...];
[self presentModalViewController:infoViewController animated:YES];
[infoViewController release];
Basically what I am trying to accomplish is an augmented reality application. I have a map view and the augmented reality view.
When the user only looks at the map view and then returns to the previous page in the UINavigation stack all location services are stopped and the arrow toolbar notification dissapears. It is when the user leaves the map view and the UIImagePickerController is presented modally the location services notification will remain even after the user presses the button that is responsible for stopping all location services and popping the current view.
I know it is not my CLLocationManager causing the problem because as I said the error doesn't occur when the UIImagePicker is never placed on the screen. My thoughts are that the location services used for geolocating or whatever the camera uses them for is not stopping even though i dimiss the modal view before popping the current view.
For the life of me I can't figure out why they arent stopping, if anyone might know why it would be a huge help.
Here is the code that I have right now in the method that is called to prepare for popping the view from the UINavigation stack
[_locationManager setDelegate:nil];
[_locationManager stopUpdatingLocation];
[_locationManager stopUpdatingHeading];
[[UIAccelerometer sharedAccelerometer] setDelegate:nil];
if (_imagePickerOn){
[self dismissModalViewControllerAnimated:YES];
_imagePickerOn = FALSE;
}
--EDIT--
Heres the method where I present the image picker, very basic:
- (IBAction) cameraButtonPressed{
_imagePickerOn = TRUE;
[self presentModalViewController:_imagePicker animated:NO];
}
I assume you’re allocating the image picker controller in advance elsewhere. That’s probably the problem—when its view goes offscreen (as you dismiss it), it’s not getting deallocated, so it’s still in memory and still presumably using its location manager. It’s a bug, but not your bug, so you’re not going to be able to do much about it with your current setup.
A more common pattern is to only allocate things like UIImagePickerController when you’re about to present them and to release them immediately after the call to -presentModalViewController:animated:. It can make your UI a little less responsive, especially when allocating complicated view controller (I’m not sure if the image picker controller qualifies as such), but you get the benefit of reduced memory usage and—hopefully—of no longer using location services when you don’t want them.
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];
}
I've finally gotten a working "alpha" version of my first app installed and (mostly) working on my iPhone 3G. So excited I came into the house and danced a little jig while my wife rolled her eyes at me. Don't care - totally stoked that I figured it out on my own (with lots of help here - thanks again, guys).
I've never really dabbled with or cared about animation; I'm more into utility-type apps. However, I've decided that I'd like to animate my app's opening image / default.png / splash screen similar to the flipside view controller animation - where the image spins from a view on the front to a different view on the back. I've found code for animating between views using the flipside animation, but how would I go about animating from a static *.png image to my navigation-based table view? I'm just not even sure where to start with this one - literally the first time I've ever even searched for anything graphics-related in the documentation.
Any help will be appreciated. As usual, thanks in advance!
You can't do anything with your Default.png, and just for form I'll point out that that HIG guidelines say that you shouldn't use it as a splash screen :-).
I would suggest that you use your initial view controller to duplicate the Default.png, and copy the flip animation code from a basic Utility app template - you probably want to use [NSObject performSelector:#selector(...) afterDelay:0] to get it to flip, called from your initial viewDidLoad:.
You can just present a modal view controller when you first launch using the flip transition instead of the default slide. Have your initial view controller loaded from your xib just display the same image you are using for your Default.png. Once you get the -viewDidLoad call in your initial view controller, push the modal view specifying the transition you want. Something like this:
- (void)showMainView;
{
MainViewController *controller = [[MainViewController alloc] init];
[controller setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:controller animated:YES];
[controller release], controller = nil;
}
As Paul suggested, you should call this using performSelector:withObject:afterDelay:
[self performSelector:#selector(showMainView) withObject:nil afterDelay:0.15];
Hope that helps.
So in my app delegate I add a call add the myViewController.view to the main window:
1. [window addSubview:myViewController.view];
In myViewController I do the following code in the viewDidAppear method:
2. [self presentModalViewController: yourViewController animated: YES];
In my yourViewController class I do the following to try and go back to the main window
3. [self dismissModalViewControllerAnimated:YES];
My main windows view appears with buttons in all, but the buttons won't react to any click or anything. It's like there is something over them that I can't see.
Also, the main windows button works before this process but doesn't after the process.
Any help would be appreciated.
If the dismiss method call is in the modal view controller (not the parent that presents it), then you actually want to call [self.parentController dismissModalViewControllerAnimated:YES];
There are a number of reasons why things might not be responding to your touches. Here are two that have happened to me:
The frame of the view you want to touch is too small. UIViews can draw outside of their frames, so it might look ok, but not respond if the touch is technically outside of the frame -- you also have to check that all the superview's up the hierarchy also have a large enough frame.
If anything in your view is a UIImageView or child thereof, it won't respond to user touches because UIImageView has userInteractionEnabled set to NO by default. You can fix this just by setting myImageView.userInteractionEnabled = YES;
Edit: Oli pointed out in the comments that dismissModalViewControllerAnimated: should work if called on either self.parentController or simply self, since that method is smart enough to call the parent if needed, according to the docs. The docs also make it sound like this might behave differently if you have multiple model views open at once, though, so I would still consider it cleaner code to call the method on self.parentController directly.