Quelqu'un d'autre a-t-il un problème avec UIImagePickerController
dans iOS 8? La méthode ci-dessous fonctionne parfaitement dans iOS 7 sur iPad, mais l'erreur suivante s'affiche lorsque j'exécute cette opération dans XCode 6 (version bêta 3 ou 4) lorsque j'essaie de présenter le sélecteur (dernière ligne). Si cela compte, la sélection du type de source provient d'un alertView présenté au même endroit.
Warning: Attempt to present <UIImagePickerController: 0x7c0ae400> on <CAGUCreateContactViewController: 0x7bf61a00> which is already presenting (null)
Méthode pour ouvrir imagePicker.
- (void)openPhotoPicker:(UIImagePickerControllerSourceType)sourceType
{
if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {
NSArray *availableMediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType];
if ([availableMediaTypes containsObject:(NSString *)kUTTypeImage]) {
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.modalPresentationStyle = UIModalPresentationFullScreen;
imagePickerController.sourceType = sourceType;
imagePickerController.mediaTypes = @[(NSString *)kUTTypeImage];
imagePickerController.delegate = self;
self.imagePickerController = imagePickerController;
if (sourceType == UIImagePickerControllerSourceTypeCamera) {
[self presentViewController:self.imagePickerController animated:YES completion:nil];
} else {
if (self.popoverVC) {
[self.popoverVC dismissPopoverAnimated:YES];
self.popoverVC = nil;
}
self.popoverVC = [[UIPopoverController alloc] initWithContentViewController:imagePickerController];
[self.popoverVC presentPopoverFromRect:self.nameAndPicCell.picture.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
}
}
}
Je pense que cela est dû au fait que dans iOS 8, les vues d'alerte et les feuilles d'action sont réellement présentées aux contrôleurs de vue (UIAlertController
). Ainsi, si vous présentez un nouveau contrôleur de vue en réponse à une action de UIAlertView
, il est présenté pendant que UIAlertController
est congédié. J'ai résolu le problème en retardant la présentation de la variable UIImagePickerController
jusqu'à la prochaine itération du runloop, en procédant comme suit:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self openPhotoPicker:sourceType];
}];
Cependant, le moyen approprié de résoudre ce problème consiste à utiliser la nouvelle API UIAlertController
sur iOS 8 (c'est-à-dire, utilisez if ([UIAlertController class])
... pour le tester). Ceci est juste une solution de contournement si vous ne pouvez pas utiliser la nouvelle API pour le moment.
Je suis d'accord avec la détection de problème Ben Lings. Je suggérerais une solution plus simple au cas où vous utiliseriez UIActionSheet. J'ai simplement déplacé mon code qui réagit à la sélection de la feuille d'action à partir de:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex;
{
// my code
}
dans:
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex; // after animation
{
// my code
}
De cette façon, l'application garantit que le code sera exécuté APRÈS la fin de l'animation UIActionSheet.
UIAlertView ayant une méthode déléguée similaire:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex; // after animation
{
// my code
}
Je suppose qu'une solution similaire peut s'appliquer.
Voici une solution qui a fonctionné pour moi
if([[[UIDevice currentDevice] systemVersion] floatValue]>=8.0)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self presentViewController:cameraUI animated:NO completion:nil];
}];
}
else{
[controller presentViewController:cameraUI animated:NO completion:nil];
}
N'oubliez pas d'allouer cameraUI
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
Construire et aller!
J'étais confronté au même problème dans iOS 8 . Ensuite, j'ai consulté le journal des modifications de la dernière mise à jour pour iOS, à savoir 8.0.2 sur l'appareil.
Il est mentionné dans cette mise à jour que_
"Corrige un problème empêchant certaines applications d'accéder aux photos de la photothèque"
Alors testez votre application en utilisant XCode 6 sur un appareil avec la version iOS 8.0.2, elle fonctionnera correctement.
Cela m'a aidé, espérons la même chose pour vous.
UIImagePickerController *imagePickerController= [[UIImagePickerController alloc] init];
[imagePickerController setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
// image picker needs a delegate so we can respond to its messages
[imagePickerController setDelegate:self];
self.shouldCallViewWillAppear = NO;
if(IS_IOS8)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Place image picker on the screen
[self presentViewController:imagePickerController animated:YES completion:nil];
}];
}
else
{
[self presentViewController:imagePickerController animated:YES completion:nil];
}
Vous pouvez ignorer le contrôleur de vue présenté (le cas échéant) en utilisant
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
Cela a fonctionné pour moi.
Tout ce que vous avez à faire est de rejeter ViewController déjà présenté:
if (self.presentedViewController) {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
[self openPhotoPicker:sourceType];
Si l'erreur persiste, mettez openPhotoPicker: dans le gestionnaire d'achèvement
Sur iOS 8, vous devez utiliser la nouvelle API:
if (SYSTEM_VERSION_IOS_8) {
self.imagePickerController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popPC = self.imagePickerController.popoverPresentationController;
popPC.barButtonItem = self.popoverItem;
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:self.imagePickerController animated:YES completion:nil]
}
Je vous recommande de regarder la session WWDC 2014 228 dans les contrôleurs de présentation latérale
J'ai eu beaucoup de peine à trouver une solution qui fonctionne à la fois sur iPad et iPhone, voici le code final dont certaines proviennent de commentaires d'autres personnes: commencer :)
définitions:
__weak IBOutlet UIButton *attachButton;
UIImage *image;
action du bouton:
- (IBAction)doAttach:(id)sender {
UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:@"Select image from" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"From library",@"From camera", nil] ;
[action showInView:self.view];
}
#pragma mark - ActionSheet delegates
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if( buttonIndex == 1 ) {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusAuthorized)
{
NSLog(@"%@", @"You have camera access");
}
else if(authStatus == AVAuthorizationStatusDenied)
{
NSLog(@"%@", @"Denied camera access");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){
NSLog(@"Granted access to %@", AVMediaTypeVideo);
} else {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“no camera access“
message: @“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
NSLog(@"Not granted access to %@", AVMediaTypeVideo);
return ;
}
}];
}
else if(authStatus == AVAuthorizationStatusRestricted)
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“no camera access“
message: @“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
NSLog(@"%@", @"Restricted, normally won't happen");
}
else if(authStatus == AVAuthorizationStatusNotDetermined)
{
NSLog(@"%@", @"Camera access not determined. Ask for permission.");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){
NSLog(@"Granted access to %@", AVMediaTypeVideo);
} else {
NSLog(@"Not granted access to %@", AVMediaTypeVideo);
return ;
}
}];
}
else
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“No camera access“
message: @“error accusing camera”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
return;
//NSLog(@"%@", @"Camera access unknown error.");
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIImagePickerController *pickerView =[[UIImagePickerController alloc]init];
pickerView.allowsEditing = YES;
pickerView.delegate = self;
pickerView.sourceType = UIImagePickerControllerSourceTypeCamera;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];
pickerView.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popPC = pickerView.popoverPresentationController;
popPC.sourceView = attachButton;
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:pickerView animated:YES completion:nil];
} else {
[self presentModalViewController:pickerView animated:YES ];
}
}
}else if( buttonIndex == 0 ) {
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
case ALAuthorizationStatusRestricted:
case ALAuthorizationStatusDenied:
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“no access to library”
message: @“if you wish to access photos in this app go to settings -> appName-> and turn on photos .”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
break;
default:
{
UIImagePickerController *pickerView = [[UIImagePickerController alloc] init];
pickerView.allowsEditing = YES;
pickerView.delegate = self;
[pickerView setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];
pickerView.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popup = pickerView.popoverPresentationController;
popup.sourceView = attachButton;
popup.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:pickerView animated:YES completion:nil];
} else {
[self presentModalViewController:pickerView animated:YES ];
}
}
break;
}
}
}
#pragma mark - PickerDelegates
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[self dismissModalViewControllerAnimated:true];
UIImage * img = [info valueForKey:UIImagePickerControllerEditedImage];
image = img;
}
J'ai simplement fait ceci:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
(unsigned long)NULL), ^(void) {
[self retractActivePopover];
dispatch_async(dispatch_get_main_queue(), ^ {
_activePopover=imagePickerPopover;
UIBarButtonItem *callingButton = (UIBarButtonItem*) sender;
[imagePickerPopover presentPopoverFromBarButtonItem:callingButton permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
});
});
Voici une solution Xamarin. Ce qui a fonctionné pour moi a été d’ajouter mes actions à un gestionnaire d’événements rejeté.
this.btnPhoto.TouchUpInside += (sender, e) =>
{
actionSheet = new UIActionSheet ("Add Photo");
actionSheet.AddButton ("Take Photo");
actionSheet.AddButton ("Select from Library");
actionSheet.AddButton ("Cancel");
actionSheet.DestructiveButtonIndex = -1; // red
actionSheet.CancelButtonIndex = 3; // black
actionSheet.Clicked += delegate(object a, UIButtonEventArgs b)
{
actionSheet.Dismissed += (object aSender, UIButtonEventArgs dismissArgs) =>
{
switch (dismissArgs.ButtonIndex)
{
case 0:
showCamera ();
break;
case 1:
showPhotoLibrary ();
break;
}
};
};
actionSheet.ShowInView (view);
};
performSelector: withObject: afterDelay a résolu mon problème.
a également faitDismissWithButtonIndex faire le tour.
Max