25

ich eine UIImagePickerController innerhalb eines UIPopoverController bin mit der perfekt mit iOS6 arbeitet. Bei iOS 7 wird das "Vorschau" -Bild gedreht, das gezeigt wird, um das Bild zu erfassen, aber wenn ich ein Bild mache, wird es korrekt gespeichert. DieseiPad iOS7 - UIImagePickerController in UIPopoverController hat falschen Vorschaubild

ist, wie ich meine Picker erhalten:

UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; 
imagePicker.delegate = self; 
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; 
imagePicker.mediaTypes = [NSArray arrayWithObjects: 
           (NSString *) kUTTypeImage, 
           nil]; 
imagePicker.allowsEditing = NO; 

Und es zu einem popover Controller hinzufügen:

self.imagePickerPopOver = [[UIPopoverController alloc] initWithContentViewController:imagePicker]; 
    [self.imagePickerPopOver presentPopoverFromRect:CGRectMake(aPosViewA.x, cameraButton_y, 100.0, 30.0) inView:self.detailViewController.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 

Die Berechnungen sind für die Schaltfläche Position in einem UIScrollView bei der die popover zeigen korrekte Position:

presentPopoverFromRect:CGRectMake(aPosViewA.x, cameraButton_y, 100.0, 30.0) 

Ich glaube nicht, dass das Problem dort liegt, wie ich o versucht habe ut mehrere Kombinationen.

Ich habe auch versucht, das Bild im Vollbild-Modus zu erfassen, aber die App ist nur zu verwenden, Landscape-Modus erlaubt. Wenn das Bild im Hochformat aufgenommen wird und die modale Ansicht nicht angezeigt wird, bleibt die App auch im Hochformat. Ich konnte keine Möglichkeit finden, den UIImagePickerController daran zu hindern, in den Hochformat-Modus zu wechseln oder die App zurück in den Querformat-Modus zu versetzen, wenn die modale Ansicht beendet wurde.

UPDATE

Ich habe die Antwort von here genommen und einen Schritt weiter gekommen.

ich verwandle die Ansicht nach den Picker zu schaffen und vor dem popover zeigt:

switch ([UIApplication sharedApplication].statusBarOrientation) { 
     case UIInterfaceOrientationLandscapeLeft: 
      self.imagePicker.view.transform = CGAffineTransformMakeRotation(M_PI/2); 
      break; 
     case UIInterfaceOrientationLandscapeRight: 
      self.imagePicker.view.transform = CGAffineTransformMakeRotation(-M_PI/2); 
      break; 
     default: 
      break; 
    } 

die so lange funktioniert, wie ich nicht um das iPad drehen sich. Denn die Ich melde mich für die Ausrichtung geändert Veranstaltung:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil]; 

und die Picker Ansicht ändern:

- (void)orientationChanged:(NSNotification *)notification{ 

    if (self.imagePicker) { 
     switch ([UIApplication sharedApplication].statusBarOrientation) { 
      case UIInterfaceOrientationLandscapeLeft: 
       self.imagePicker.view.transform = CGAffineTransformMakeRotation(M_PI/2); 
       break; 
      case UIInterfaceOrientationLandscapeRight: 
       self.imagePicker.view.transform = CGAffineTransformMakeRotation(-M_PI/2); 
       break; 
      default: 
       break; 
     } 
    } 
} 

verbleibendes Problem: Wie ich am Anfang geschrieben, wenn das Bild aufgenommen wurde, war es korrekt angezeigt, um es zu akzeptieren oder zu verwerfen. Dies ist jetzt auch transformiert. Irgendwie muss ich wissen, wann das Bild aufgenommen wurde und es zurück verwandeln.

UND, das ist wirklich ein hässlicher Hack und wird wahrscheinlich nicht mit dem nächsten iOS Update funktionieren. Hat jemand eine Idee, wie man das sauberer umsetzen kann?

UPDATE 2

Auch die böse war, habe ich eine saubere Lösung gefunden, die mein Problem löst, aber ist nicht die Antwort auf die erste Frage in Bezug auf eine imagepicker in einem popover-Controller, der von Apple ist nicht zu empfehlen, aber dürfen.

Ich habe jetzt die UIImagePickerController wie diese subclassed:

@implementation QPImagePickerController 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { 
    return UIInterfaceOrientationIsLandscape(toInterfaceOrientation); 
} 

- (BOOL)shouldAutorotate { 
    return YES; 
} 

- (NSUInteger)supportedInterfaceOrientations{ 
    return UIInterfaceOrientationMaskLandscape; 
} 

@end 

und ich bin mit dem imagepicker im Vollbild statt in einem popover. Getestet bisher in iOS7.

+2

Ich bin mit genau dem gleichen Problem konfrontiert. Ich kann nicht glauben, dass das kein relevanteres Thema ist - wie bricht es nicht mehr Apps? – daveMac

+0

Genau dasselbe Problem, wird dies nicht im nächsten Update behoben werden? – user1838169

+0

Es sieht so aus, als ob das gleiche Problem die Facebook-App von ios7 betrifft, die eine Popup-Kamera benutzt. – Mike

Antwort

13

Die UIImagePickerController hat eine Eigenschaft namens cameraViewTransform.Wenn Sie ein CGAffineTransform-Objekt darauf anwenden, wird das Vorschaubild transformiert, aber das aufgenommene Bild wird nicht transformiert und daher korrekt erfasst. Ich habe das gleiche Problem, das Sie beschreiben, und ich löste es (für iOS7) von meiner Kamerasteuerung zu schaffen und es in einem popover Platzierung wie folgt:

UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; 

[imagePickerController setDelegate:self]; 

imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; 

CGFloat scaleFactor=1.3f; 

switch ([UIApplication sharedApplication].statusBarOrientation) { 

     case UIInterfaceOrientationLandscapeLeft: 

      imagePickerController.cameraViewTransform = CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI * 90/180.0), scaleFactor, scaleFactor); 

      break; 

     case UIInterfaceOrientationLandscapeRight: 

      imagePickerController.cameraViewTransform = CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI * -90/180.0), scaleFactor, scaleFactor); 

      break; 

     case UIInterfaceOrientationPortraitUpsideDown: 

      imagePickerController.cameraViewTransform = CGAffineTransformMakeRotation(M_PI * 180/180.0); 

      break; 

      default: 
       break; 
     } 

__popoverController = [[UIPopoverController alloc] initWithContentViewController:imagePickerController]; 

[__popoverController presentPopoverFromRect:presentationRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 

ich das Bild auch, wenn im Querformat skalieren, so dass es das füllt Sucher mehr als sonst. Meiner Meinung nach ist das alles ziemlich eklig, aber ich werde es hoffentlich wieder entfernen können, sobald iOS7.1 eintrifft.

3

Ich habe eine andere Lösung gefunden, die den Fall behandelt, in dem ein Gerät gedreht wird, während das UIIMagePickerView auf der Grundlage der Antwort Journeyman präsentiert wird. Es behandelt auch den Fall, in dem die Ansicht von UIOrientationLandscapeRight/UIOrientationLandscapeLeft zurück zu UIOrientationPortrait gedreht wird.

habe ich eine Unterklasse von UIImagePickerController:

#import <UIKit/UIKit.h> 

@interface PMImagePickerController : UIImagePickerController 

@end 

registriert es dann Benachrichtigung zu erhalten, wenn die Geräteausrichtung ändert:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fixCameraOrientation:) name:UIDeviceOrientationDidChangeNotification object:nil]; 

Der Selektor fixCameraOrientation enthält Code des Journeyman mit einem zusätzlichen Fall, eingewickelt in Überprüfen Sie, ob der sourceType die Kamera ist:

- (void)fixCameraOrientation:(NSNotification*)notification 
{ 
    if (self.sourceType == UIImagePickerControllerSourceTypeCamera) { 
     CGFloat scaleFactor=1.3f; 

     switch ([UIApplication sharedApplication].statusBarOrientation) { 
      case UIInterfaceOrientationLandscapeLeft: 
       self.cameraViewTransform = CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI * 90/180.0), scaleFactor, scaleFactor); 
       break; 


      case UIInterfaceOrientationLandscapeRight: 
       self.cameraViewTransform = CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI * -90/180.0), scaleFactor, scaleFactor); 
       break; 

      case UIInterfaceOrientationPortraitUpsideDown: 
       self.cameraViewTransform = CGAffineTransformMakeRotation(M_PI * 180/180.0); 
       break; 

      case UIInterfaceOrientationPortrait: 
       self.cameraViewTransform = CGAffineTransformIdentity; 
       break; 

      default: 
       break; 
     } 
    } 

} 

Der wichtige Fall ist hier der Fall, in dem die Geräteausrichtung auf Hochformat gesetzt wird. Die Ansicht des Overlays muss in diesem Fall zurückgesetzt werden. Es ist auch wichtig für die fixCameraOrientation Wähler nach der Bild Picker Ansicht Lasten, falls aufgerufen werden das Gerät gedreht wird:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    [self fixCameraOrientation:nil]; 
} 
1

iPad mit Kamera - nicht angezeigt in einem popover. Stattdessen in einem modalen Ansicht Controller, wie Sie auf dem iPhone. (zumindest beginnend mit iOS 7)

+0

genau was ich brauchte. Scheint in iOS 8 iPad Landschaft, die Popover ist am besten für die Bibliothek, aber modale Ansicht Präsentation ist besser für die Kamera. – Codezy

2

Ich hatte eine ähnliche Situation in meiner App. Die Vorschau rotierte jedoch korrekt in iOS7 und nicht in iOS8. In diesem Code wird davon ausgegangen, dass Sie mehr als eine Ausrichtung haben.

Die erste Sache ist die Unterklasse UIImagePickerController.

Beginnen Sie von oben, fügen Sie Ihrer .m-Datei #import <AVFoundation/AVFoundation.h> hinzu.

Fügen Sie auch eine Eigenschaft zum Speichern der ursprünglichen Ausrichtung @property (nonatomic) UIInterfaceOrientation startingOrientation; und eine andere für eine Bedingung zum Entfernen von Clipping @property (nonatomic) BOOL didAttemptToRemoveCropping;.

Wir hörten ein paar Benachrichtigungen. UIApplicationDidChangeStatusBarOrientationNotification ist offensichtlich auf die Gerätedrehung zu hören. AVCaptureSessionDidStartRunningNotification heißt richtig, wenn die Kamera mit der Aufnahme beginnt.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationDidChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionDidStart:) name:AVCaptureSessionDidStartRunningNotification object:nil]; 

Im -captureSessionDidStart: eine Bedingung hinzufügen, die Aussicht ist tatsächlich auf dem Bildschirm, um zu überprüfen und sicherzustellen, dass die Kamera soll if (self.view.window && self.sourceType == UIImagePickerControllerSourceTypeCamera) angezeigt werden soll. Wenn ja, stellen Sie die Startausrichtung self.startingOrientation = [UIApplication sharedApplication].statusBarOrientation; ein.

In der -statusBarOrientationDidChange: fügen Sie die gleiche Bedingung wie oben, aber dieses Mal, wenn wahr, aktualisieren wir die Kamera zu transformieren. Zuerst erhalten wir die Offset-Rotation basierend auf der anfänglichen Rotation. Dies wird benötigt, wenn Sie die UIImagePickerController in andere Ausrichtungen als Hochformat eingeben.

CGFloat startingRotation = ({ 
    CGFloat rotation; 

    switch (self.startingOrientation) { 
     case UIInterfaceOrientationPortraitUpsideDown: 
      rotation = M_PI; 
      break; 
     case UIInterfaceOrientationLandscapeLeft: 
      rotation = -M_PI_2; 
      break; 
     case UIInterfaceOrientationLandscapeRight: 
      rotation = M_PI_2; 
      break; 
     default: 
      rotation = 0.0f; 
      break; 
    } 

    rotation; 
}); 

Als nächstes aktualisieren wir die Kamera mit der aktuellen Rotation transformieren.

self.cameraViewTransform = CGAffineTransformMakeRotation(({ 
    CGFloat angle; 

    switch ([UIApplication sharedApplication].statusBarOrientation) { 
     case UIInterfaceOrientationPortraitUpsideDown: 
      angle = startingRotation + M_PI; 
      break; 
     case UIInterfaceOrientationLandscapeLeft: 
      angle = startingRotation + M_PI_2; 
      break; 
     case UIInterfaceOrientationLandscapeRight: 
      angle = startingRotation + -M_PI_2; 
      break; 
     default: 
      angle = startingRotation; 
      break; 
    } 

    angle; 
})); 

Und wir werden schließlich versuchen, die schwarzen Balken in beide 90-Grad-Orientierung von der Startorientierung präsentiert zu entfernen. (Dies ist möglicherweise nur ein iOS8-Problem.) Etwas detaillierter, wenn ich den UIImagePickerController im Hochformat-Modus eingebe und dann auf Querformat umstelle, erscheinen oben und unten in der Vorschau schwarze Balken. Die Lösung hierfür ist nicht maßstabsgetreu, sondern um das Clipping einer Superview zu entfernen. Wir müssen diesen Versuch nur einmal durchführen, also prüfen Sie zuerst, ob wir diesen Code aufgerufen haben. Stellen Sie außerdem sicher, dass wir diesen Code nur aufrufen, wenn wir uns gedreht haben. Wenn es in der anfänglichen Orientierung aufgerufen wird, wird es nicht sofort funktionieren.

if (!self.didAttemptToRemoveCropping && self.startingOrientation != [UIApplication sharedApplication].statusBarOrientation) { 
    self.didAttemptToRemoveCropping = YES; 

    [self findClippedSubviewInView:self.view]; 
} 

schließlich im Code für -findClippedSubviewInView: wir eine Schleife durch alle Subviews mit .clipsToBounds = YES für eine Ansicht zu suchen. Wenn das wahr ist, machen wir noch eine weitere Bedingung, um zu bestätigen, dass eine ihrer übergeordneten Übersichten korrekt ist.

for (UIView* subview in view.subviews) { 
    if (subview.clipsToBounds) { 
     if ([self hasAncestorCameraView:subview]) { 
      subview.clipsToBounds = NO; 
      break; 
     } 
    } 

    [self findClippedSubviewInView:subview]; 
} 

Im -hasAncestorCameraView: wir einfach Schleife die Superkette und return true, wenn eine der Klassen CameraView im Namen hat.

if (view == self.view) { 
    return NO; 
} 

NSString* className = NSStringFromClass([view class]); 

if ([className rangeOfString:@"CameraView"].location != NSNotFound) { 
    return YES; 

} else { 
    return [self hasAncestorCameraView:view.superview]; 
} 

Das ist die Aufschlüsselung des Codes, hier ist alles zusammen.

#import <AVFoundation/AVFoundation.h> 
#import "GImagePickerController.h" 

@interface GImagePickerController() 
@property (nonatomic) UIInterfaceOrientation startingOrientation; 
@property (nonatomic) BOOL didAttemptToRemoveCropping; 
@end 

@implementation GImagePickerController 

- (instancetype)init { 
    self = [super init]; 
    if (self) { 

     if ([[[UIDevice currentDevice] systemVersion] intValue] >= 8) { 
      [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationDidChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 
      [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionDidStart:) name:AVCaptureSessionDidStartRunningNotification object:nil]; 
     } 

    } 
    return self; 
} 

- (void)dealloc { 
    if ([[[UIDevice currentDevice] systemVersion] intValue] >= 8) { 
     [[NSNotificationCenter defaultCenter] removeObserver:self]; 
    } 
} 


#pragma mark - Capture Session 

- (void)captureSessionDidStart:(NSNotification *)notification { 
    if (self.view.window && self.sourceType == UIImagePickerControllerSourceTypeCamera) { 
     [self updateStartingOrientation]; 
    } 
} 


#pragma mark - Orientation 

- (void)updateStartingOrientation { 
    self.startingOrientation = [UIApplication sharedApplication].statusBarOrientation; 
    [self updateCameraTransform]; 
} 

- (void)updateCameraTransform { 
    CGFloat startingRotation = ({ 
     CGFloat rotation; 

     switch (self.startingOrientation) { 
      case UIInterfaceOrientationPortraitUpsideDown: 
       rotation = M_PI; 
       break; 
      case UIInterfaceOrientationLandscapeLeft: 
       rotation = -M_PI_2; 
       break; 
      case UIInterfaceOrientationLandscapeRight: 
       rotation = M_PI_2; 
       break; 
      default: 
       rotation = 0.0f; 
       break; 
     } 

     rotation; 
    }); 

    self.cameraViewTransform = CGAffineTransformMakeRotation(({ 
     CGFloat angle; 

     switch ([UIApplication sharedApplication].statusBarOrientation) { 
      case UIInterfaceOrientationPortraitUpsideDown: 
       angle = startingRotation + M_PI; 
       break; 
      case UIInterfaceOrientationLandscapeLeft: 
       angle = startingRotation + M_PI_2; 
       break; 
      case UIInterfaceOrientationLandscapeRight: 
       angle = startingRotation + -M_PI_2; 
       break; 
      default: 
       angle = startingRotation; 
       break; 
     } 

     angle; 
    })); 

    if (!self.didAttemptToRemoveCropping && self.startingOrientation != [UIApplication sharedApplication].statusBarOrientation) { 
     self.didAttemptToRemoveCropping = YES; 

     [self findClippedSubviewInView:self.view]; 
    } 
} 

- (void)statusBarOrientationDidChange:(NSNotification *)notification { 
    if (self.view.window && self.sourceType == UIImagePickerControllerSourceTypeCamera) { 
     [self updateCameraTransform]; 
    } 
} 


#pragma mark - Remove Clip To Bounds 

- (BOOL)hasAncestorCameraView:(UIView *)view { 
    if (view == self.view) { 
     return NO; 
    } 

    NSString* className = NSStringFromClass([view class]); 

    if ([className rangeOfString:@"CameraView"].location != NSNotFound) { 
     return YES; 

    } else { 
     return [self hasAncestorCameraView:view.superview]; 
    } 
} 

- (void)findClippedSubviewInView:(UIView *)view { 
    for (UIView* subview in view.subviews) { 
     if (subview.clipsToBounds) { 
      if ([self hasAncestorCameraView:subview]) { 
       subview.clipsToBounds = NO; 
       break; 
      } 
     } 

     [self findClippedSubviewInView:subview]; 
    } 
} 

@end 
+0

funktioniert fast perfekt, es sieht ein bisschen seltsam aus, da es scheint, als ob es mehr Rotationen als nötig macht – TMob

Verwandte Themen