25

Tôi đang sử dụng UIImagePickerController trong UIPopoverController đang hoạt động hoàn hảo với iOS6. Với iOS 7 ảnh "xem trước" được hiển thị để chụp ảnh được xoay, nhưng nếu tôi chụp ảnh, ảnh sẽ được lưu chính xác.iPad iOS7 - UIImagePickerController trong UIPopoverController có hình ảnh xem trước sai

Đây là cách tôi nhận được bảng chọn của tôi:

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

Và thêm nó vào một bộ điều khiển popover:

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]; 

Đó là những tính toán cho các vị trí nút ở một UIScrollView để hiển thị các popover tại vị trí chính xác:

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

Tôi không nghĩ rằng vấn đề nằm ở đó như tôi đã thử o ut một số kết hợp.

Tôi cũng đã cố chụp ảnh ở chế độ toàn màn hình nhưng ứng dụng chỉ được phép sử dụng chế độ ngang. Nếu hình ảnh được chụp ở chế độ dọc và chế độ xem phương thức bị loại bỏ, ứng dụng sẽ vẫn ở chế độ dọc. Tôi không thể tìm thấy cách để ngăn UIImagePickerController chuyển sang chế độ dọc hoặc buộc ứng dụng quay lại chế độ nằm ngang nếu chế độ xem phương thức bị loại bỏ.

CẬP NHẬT

Tôi đã lấy câu trả lời từ here và tiến thêm một bước nữa.

tôi chuyển đổi quan điểm sau khi tạo bảng chọn và trước khi hiển thị các popover:

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; 
    } 

mà làm việc miễn là tôi không quay lại iPad. Cho rằng tôi đang đăng ký tham gia thay đổi sự kiện định hướng:

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

và thay đổi quan điểm chọn:

- (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; 
     } 
    } 
} 

CÒN VẤN ĐỀ: Như tôi đã viết trong đầu, khi bức ảnh được chụp, đó là được hiển thị chính xác để chấp nhận hoặc loại bỏ nó. Điều này bây giờ được chuyển đổi là tốt. Bằng cách nào đó tôi cần phải biết khi nào hình ảnh được chụp và biến nó trở lại.

VÀ, đây thực sự là một bản hack khó chịu và có thể sẽ không hoạt động với Bản cập nhật iOS tiếp theo. Có ai là một ý tưởng làm thế nào để thực hiện điều đó một cách sạch hơn?

UPDATE 2

Đây là quá khó chịu, tôi đã tìm thấy một giải pháp sạch hơn mà giải quyết vấn đề của tôi, nhưng không phải là câu trả lời cho câu hỏi ban đầu về một imagepicker trong một bộ điều khiển popover, mà không được khuyến khích bởi Apple, nhưng được phép.

Tôi đã subclassed nay là UIImagePickerController như thế này:

@implementation QPImagePickerController 

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

- (BOOL)shouldAutorotate { 
    return YES; 
} 

- (NSUInteger)supportedInterfaceOrientations{ 
    return UIInterfaceOrientationMaskLandscape; 
} 

@end 

và tôi đang sử dụng imagepicker trong toàn màn hình thay vì trong một popover. Đã thử nghiệm cho đến nay trong iOS7.

+2

Tôi đang đối mặt với cùng một vấn đề. Tôi không thể tin rằng đây không phải là vấn đề liên quan hơn — làm cách nào để không phá vỡ nhiều ứng dụng hơn? – daveMac

+0

Chính xác cùng một vấn đề, điều này sẽ không được khắc phục trong bản cập nhật tiếp theo? – user1838169

+0

Dường như với tôi cùng một vấn đề đang ảnh hưởng đến ứng dụng ios7 facebook sử dụng máy ảnh bật lên. – Mike

Trả lời

13

UIImagePickerController có thuộc tính được gọi là cameraViewTransform.Áp dụng CGAffineTransform cho điều này sẽ biến đổi hình ảnh xem trước nhưng sẽ không biến đổi hình ảnh đã chụp, do đó sẽ được chụp chính xác. Tôi có cùng một vấn đề mà bạn mô tả và tôi giải quyết nó (ví iOS7) bằng cách tạo ra bộ điều khiển máy ảnh của tôi và đặt nó trong một popover như sau:

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]; 

Tôi cũng chia tỷ lệ ảnh khi ở Landscape để nó lấp đầy kính ngắm nhiều hơn nó sẽ khác. Để tâm trí của tôi này là tất cả khá khó chịu, nhưng tôi hy vọng sẽ có thể loại bỏ nó một khi iOS7.1 đến.

3

Tôi đã tìm thấy một giải pháp khác xử lý trường hợp thiết bị được xoay trong khi UIIMagePickerView trình bày dựa trên câu trả lời mà Journeyman cung cấp. Nó cũng xử lý trường hợp khung nhìn được quay từ UIOrientationLandscapeRight/UIOrientationLandscapeLeft quay lại UIOrientationPortrait.

Tôi tạo ra một lớp con của UIImagePickerController:

#import <UIKit/UIKit.h> 

@interface PMImagePickerController : UIImagePickerController 

@end 

Sau đó đăng ký nó để nhận thông báo nếu hướng thiết bị thay đổi:

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

Bộ chọn fixCameraOrientation chứa mã Journeyman với một trường hợp bổ sung, được bọc trong séc để đảm bảo sourceType là máy ảnh:

- (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; 
     } 
    } 

} 

Trường hợp quan trọng ở đây là trường hợp hướng thiết bị chuyển sang dọc. Chế độ xem lớp phủ cần được đặt lại trong trường hợp này. Nó cũng quan trọng đối với selector fixCameraOrientation được gọi sau khi xem tải chọn hình ảnh, trong trường hợp các thiết bị có thể xoay:

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

iPad với máy ảnh - không hiển thị trong một popover. Thay vào đó, trình bày trong một bộ điều khiển xem phương thức, giống như bạn sẽ làm trên iPhone. (ít nhất bắt đầu với iOS 7)

+0

chính xác những gì tôi cần. Dường như trong bối cảnh iPad 8 của iPad, popover là tốt nhất cho thư viện nhưng cách trình bày chế độ xem phương thức thì tốt hơn cho máy ảnh. – Codezy

2

Tôi có tình huống tương tự trong ứng dụng của mình. Tuy nhiên, bản xem trước đã quay chính xác trong iOS7 chứ không phải trong iOS8. Mã này giả định bạn có nhiều định hướng.

Điều đầu tiên là phân lớp UIImagePickerController.

Bắt đầu từ trên cùng, thêm #import <AVFoundation/AVFoundation.h> vào tệp .m của bạn.

Đồng thời thêm thuộc tính để lưu hướng ban đầu @property (nonatomic) UIInterfaceOrientation startingOrientation; và một thuộc tính khác để loại bỏ điều kiện cắt bớt @property (nonatomic) BOOL didAttemptToRemoveCropping;.

Sẽ nghe một vài thông báo. UIApplicationDidChangeStatusBarOrientationNotification rõ ràng là để nghe xoay vòng thiết bị. AVCaptureSessionDidStartRunningNotification được gọi ngay khi camera bắt đầu chụp.

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

Trong -captureSessionDidStart: thêm một điều kiện để xác minh xem là thực sự trên màn hình và để đảm bảo máy ảnh được cho là sẽ được hiển thị if (self.view.window && self.sourceType == UIImagePickerControllerSourceTypeCamera). Nếu vậy, hãy đặt hướng bắt đầu self.startingOrientation = [UIApplication sharedApplication].statusBarOrientation;.

Trong -statusBarOrientationDidChange: thêm điều kiện tương tự như trên, nhưng lần này nếu đúng, chúng tôi sẽ cập nhật biến đổi máy ảnh. Đầu tiên, chúng ta có được phép xoay vòng dựa trên vòng quay ban đầu. Điều này là cần thiết khi bạn nhập UIImagePickerController trong các hướng khác rồi nhấn vào chân dung.

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; 
}); 

Tiếp theo, chúng tôi sẽ cập nhật biến đổi máy ảnh với xoay hiện tại.

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; 
})); 

Và cuối cùng chúng tôi sẽ cố gắng xóa các thanh màu đen được trình bày theo hướng 90 độ từ hướng bắt đầu. (Điều này có thể chỉ là vấn đề iOS8.) Chi tiết hơn một chút, nếu tôi nhập UIImagePickerController ở chế độ dọc và sau đó xoay sang ngang, sẽ có các thanh màu đen ở trên cùng và dưới cùng của bản xem trước. Các giải pháp cho điều này không phải là để quy mô mà là để loại bỏ các clipping của một superview. Chúng tôi chỉ cần thực hiện lần thử này một lần, vì vậy trước tiên hãy kiểm tra xem chúng tôi đã gọi mã này chưa. Ngoài ra, hãy đảm bảo rằng chúng tôi chỉ gọi mã này nếu chúng tôi đã xoay vòng. Nếu nó được gọi theo hướng ban đầu thì nó sẽ không hoạt động ngay lập tức.

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

    [self findClippedSubviewInView:self.view]; 
} 

Cuối cùng trong mã cho -findClippedSubviewInView: chúng ta lặp qua tất cả các subviews để tìm kiếm một cái nhìn với .clipsToBounds = YES. Nếu đó là sự thật, chúng tôi thực hiện thêm một điều kiện để xác minh một trong những giám sát tổ tiên của nó là chính xác.

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

    [self findClippedSubviewInView:subview]; 
} 

Trong -hasAncestorCameraView: chúng tôi chỉ đơn giản là vòng lên chuỗi SuperView và trả về true nếu một trong các lớp có CameraView trong tên.

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]; 
} 

Đó là sự cố mã, dưới đây là tất cả cùng nhau.

#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

hoạt động gần như hoàn hảo, có vẻ hơi lạ, vì nó có vẻ như xoay vòng nhiều hơn mức cần thiết – TMob

Các vấn đề liên quan