I'm currently writing an iOS app wherein I want to let the user pick an image from their photo library. I don't want them to be able to take a new photo or edit the existing one, but that's unimportant right now. Since this is an iPad app, I have to show the UIImagePickerController view in a popover view (or an exception is thrown, etc.). This is the code I am currently using to try to achieve that:
- (void)viewDidLoad{
[super viewDidLoad];
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){
_picker = [[UIImagePickerController alloc] initWithRootViewController:self];
_picker.delegate = self;
}else{
[[[UIAlertView alloc] initWithTitle:#"goto fail;" message:nil delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil] show];
}
self.view.backgroundColor = [UIColor purpleColor];
}
- (void)viewDidAppear:(BOOL)animated{
popoverController = [[UIPopoverController alloc] initWithContentViewController:_picker];
[popoverController presentPopoverFromRect:(CGRect){CGPointZero, {1, 1}} inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:animated];
[super viewDidAppear:animated];
}
I expect this to show an image picker view in a popover, obviously. Instead, I get this:
This code is running on a real iPad, not in the simulator. I have never been prompted to grant access to my photos, and there is no entry for the app in the photo area of the privacy settings of Preferences.app. I am testing this on an iPad 4 (which has a camera), and cannot test in the simulator, as it is having issues at the moment. I'm not really sure where the issue could be coming from - it's quite perplexing.
Also you should specify UIImagePicker's sourceType.
_picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
UPDATE
Initialise picker this way:
_picker = [[UIImagePickerController alloc] init];
Related
My app is structured with a central view controller that adds 3 to 4 subviews to the main view. In one of the added view controllers I present a camera to the user. When I dismiss the image picker, every subview except the one in which I present the camera (the view controller) disappears. I think it might be related to how the app is structured and the view stack. The app works fine when running iOS 8 on an iPhone and iOS 7 on an iPad. I am having this issue only when I am running iOS 8 on the iPad. I made sure the code followed the apple documentation on how to present and dismiss the image picker. Here is the code used to present the image picker.
-(IBAction)photoButtonPressed:(id)sender
{
// Prompt for camera or photo library
// Retrieve image and set it as this button's default image
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIImagePickerController *imagePicker =
[[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.mediaTypes = [NSArray arrayWithObjects:
(NSString *) kUTTypeImage, nil];
imagePicker.allowsEditing = NO;
imagePicker.modalPresentationStyle = UIModalPresentationFullScreen; //play around with this
[self presentViewController:imagePicker animated:YES completion:nil];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Camera not found" message:#"There is no camera available on this device." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
Code used to dismiss
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
CGSize scaleSize = CGSizeMake(1024.0f, 1280.0f);
UIImage *capturedImage;
// Handle a still image capture
capturedImage = (UIImage *) [info objectForKey:
UIImagePickerControllerOriginalImage];
[self dismissViewControllerAnimated:YES completion:nil];
if (capturedImage) {
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
photoData = UIImageJPEGRepresentation([capturedImage resizedImage:scaleSize interpolationQuality:kCGInterpolationHigh], 5);
photoEntity = nil;
[self.takePhotoButton setImage:[UIImage imageWithData:photoData ] forState:UIControlStateNormal];
if ([self isAnyButtonSelected] || ![_answerTextField.text isEqualToString:#""] || !_questionBoolean.hidden) {
[Tools enableControl:_saveButton];
}
} else {
newPhotoData = UIImageJPEGRepresentation([capturedImage resizedImage:scaleSize interpolationQuality:kCGInterpolationHigh], 5);
photoEntity = nil;
}
}
}
And here I tried messing with the parent views and controllers in this method. I was able to get the app to return to the central view controller minus the current view controller that is in charge of taking the photos. The only problem is that the app's touch is now disabled and I am missing one view.
- (void) imagePickerControllerDidCancel: (UIImagePickerController *) picker
{
// [self willMoveToParentViewController:nil];
// [picker.view removeFromSuperview];
// [picker removeFromParentViewController];
[self dismissViewControllerAnimated:YES completion:nil];
}
I was going to post photos but I am currently unable to because I am new to stack overflow. Any help would be appreciated. Thanks!
Ok so the app is not using story boards but it is using xib files. It is inherited code and the app was created several years ago. There are multiple view controllers with multiple views. There is a central view controller where all the other view controllers are added to the central view.
[self.view addSubview:_catViewController.tableView];
[self.view addSubview:_listViewController.tableView];
[self.view addSubview:_queryViewController.view];
[self.view bringSubviewToFront:_queryViewController.view];
queryViewController is where I am taking the photo. When I dismiss every view is gone except the query view controller which happens to take up the entire screen (it previously did not). Let me know if I need to add more information! Thanks
So, the general problem is that your central view controller is adding the views of other view controllers to itself. You can't do that -- it breaks view controller encapsulation. And when you violate encapsulation, stuff just breaks. (That's a vague statement, but 100% true :-p) Unfortunately, you either need to stab in the dark to find a hack to make it work, or repartition the problem to respect encapsulation. The latter is probably better if you'll need to maintain this code in the future.
When a user clicks a certain button,I want him to have the ability to choose between taking a picture and choosing a picture from a gallery. As of right now it seems to be one or the other. Should I create two buttons for this or is there a better what to accomplish this? I am hoping a way to click a button and iOS will natively give the user the choice.
-(IBAction)takePhoto:(id)sender
{
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
// image picker needs a delegate,
[imagePickerController setDelegate:self];
// Place image picker on the screen
[self presentModalViewController:imagePickerController animated:YES];
}
In my opinion the best way would be to Create for example 2 buttons
UIBarButtonItem * choosePhotoBtn
UIBarButtonItem * TakePhotoBtn
Then call the same IBAction when pressing either button, and put a condition in it to call the appropriate interface somehting like this:
-(IBAction) getPhoto:(id) sender {
UIImagePickerController * picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
if((UIBarButtonItem *) sender == choosePhotoBtn) {
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
} else {
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
[self presentViewController:picker animated:YES completion:nil];
}
But these are the best options, I like the UIAlertView the most to be honest
To be honest thats more clicks for the user, but again thats my opinion .
Here's how you can do it, Create your UIAlertView , then put a condition in its deleguate method:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString *BtnSelected = [alertView buttonTitleAtIndex:buttonIndex];
if([BtnSelected isEqualToString:#"choosePhotoBtn"] {
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
} else {
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
[self presentViewController:picker animated:YES completion:nil];
}
When user press the button you can display UIAlertView or UIActionSheet, I would recommended UIAlertView for two button. And in the delegate method base on user selection you can make your logic to access camera or gallery.
There are two options -
First show the pickerController with source type as photo library. Then there is a property in UIImagePickerController called cameraOverlayView. You can set it to a custom view with the button at the bottom that on click switches the pickerController source type to camera.
Read the photo library and present them for selection in a custom view with a button to launch camera which would use the UIImagePickerController with sourceType as camera.
More about overlayView - [UIImagePickerController cameraOverlayView]
Sample code project from Apple - Using UIImagePickerController to Select Pictures and Take Photos
I am trying to open a UIImagePickerControllerSourceTypeCamera into a small popup subview, however every time I try this it simply goes to full screen camera... This is the first time I have tried using the camera I have read all of the docs in the developers site and I just cannot find anything explaning how to do what I would like to do.
Below is my startCamera method, in which i create a subview, then create the cameraView add the cameraView to the small subview then i load it onto the main UIView.... however as said above it goes full screen everytime :(
any help making this cameraView look like a small popup view would be greatly appreciated.
#pragma StartCamera
- (IBAction)startCamera:(id)sender {
if (isCameraViewLoaded == NO) {
// Load View for camera
cameraView = [[UIView alloc] initWithFrame:CGRectMake(100.0, 100.0, 200.0, 100.0)];
cameraView.backgroundColor = [UIColor greenColor];
// imagepicker stuff
// check for rear facing camera to continue
if( [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear])
{
// load imagePickController into subview
UIImagePickerController *imagePickController=[[UIImagePickerController alloc]init];
imagePickController.sourceType=UIImagePickerControllerSourceTypeCamera;
imagePickController.delegate=self;
imagePickController.allowsEditing=TRUE;
imagePickController.modalPresentationStyle = UIModalPresentationCurrentContext;
[cameraView addSubview:imagePickController.view];
}
else {
// if there is no camera on the device give warning
UIAlertView *noCameraAlert = [[UIAlertView alloc] initWithTitle:#"Incompatible Device" message:#"Sorry, This feature requiers a rear facing camera" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[noCameraAlert show];
}
// pass camera View to mainview
[self.view addSubview:cameraView];
isCameraViewLoaded = YES;
}else{
[cameraView removeFromSuperview];
isCameraViewLoaded = NO;
}
}
Is it possible to have a series of images (pngs) that can be positioned either over the top of an image taken in app or just appear on the screen when in camera mode in app? ie a door or wallpaper sample.
If so how might this be achieved?
Thanks for any help given :)
UIImagePickerController has a cameraOverlayView UIView property. Assign it whatever you want to be on top of the camera.
From the docs:
You can use an overlay view to present a custom view hierarchy on top of the default image picker interface. The image picker layers your custom overlay view on top of the other image picker views and positions it relative to the screen coordinates. If you have the default camera controls set to be visible, incorporate transparency into your view, or position it to avoid obscuring the underlying content.
This may help you.
-(IBAction)loadCameraView:(id)sender
{
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront])
{
[imagePicker setCameraDevice:UIImagePickerControllerCameraDeviceFront];
}
else
{
[imagePicker setCameraDevice:UIImagePickerControllerCameraDeviceRear];
}
[imagePicker setCameraCaptureMode:UIImagePickerControllerCameraCaptureModePhoto];
[imagePicker setDelegate:self];
[self presentViewController:imagePicker animated:YES completion:nil];
}
else
{
UIAlertView *aview = [[UIAlertView alloc] initWithTitle:#"Camera Not Available" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[aview show];
}
}
I have been beating my head on this for a few hours. I have some sample code (using a UINavigationController) when the view loads the camera roll will be presented. However, when I try to incorporate the same code into my app, which has a tabBarController, I get a blank modal UIImagePickerController. I didn't track down what I am doing wrong.
// bring up image picker
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeSavedPhotosAlbum]) {
NSLog(#"UIImagePickerControllerSourceTypePhotoLibrary available");
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.delegate = self;
ipc.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
ipc.allowsEditing = YES;
[self.tabBarController presentModalViewController:ipc animated:YES];
[ipc release];
}
Any insight would be appreciated.
Not sure what has changed, but this is possible by calling presentViewController from your tabBarController. This is the standard now and ensures your camera or image picker always gets presented as a full screen modal view.
For reference: presentViewController