UIPopoverController中的iPad iOS7-UIImagePickerController的预览图像错误

UIPopoverController中的iPad iOS7-UIImagePickerController的预览图像错误,ios,uiimagepickercontroller,ios7,uipopovercontroller,uiinterfaceorientation,Ios,Uiimagepickercontroller,Ios7,Uipopovercontroller,Uiinterfaceorientation,我正在UIPopoverController中使用UIImagePickerController,它与iOS6完美配合。在iOS 7中,显示用于捕获图像的“预览”图像会旋转,但如果我拍摄了一张照片,它会正确保存 这是我如何得到我的选择器: UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; imagePicker.delegate = self; imagePicker.sourceType

我正在UIPopoverController中使用UIImagePickerController,它与iOS6完美配合。在iOS 7中,显示用于捕获图像的“预览”图像会旋转,但如果我拍摄了一张照片,它会正确保存

这是我如何得到我的选择器:

UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.mediaTypes = [NSArray arrayWithObjects:
                              (NSString *) kUTTypeImage,
                              nil];
imagePicker.allowsEditing = NO;
并将其添加到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];
#import <UIKit/UIKit.h>

@interface PMImagePickerController : UIImagePickerController

@end
这些是UIScroll视图中按钮位置的计算,以显示正确位置的popover:

presentPopoverFromRect:CGRectMake(aPosViewA.x, cameraButton_y, 100.0, 30.0)
我不认为问题出在那里,因为我已经尝试了几种组合

我也尝试过在全屏模式下拍摄图像,但该应用程序只允许使用横向模式。如果图像是在纵向模式下拍摄的,并且模式视图被取消,则应用程序也将保持纵向模式。如果模式视图被取消,我无法找到阻止UIImagePickerController切换到纵向模式或强制应用程序返回横向模式的方法

更新

我已经从中得到了答案,并且更进一步

我在创建选择器之后和显示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;
    }
只要我不转动iPad,它就能工作。为此,我正在注册方向更改活动:

[[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(orientationChanged:)  name:UIDeviceOrientationDidChangeNotification  object:nil];
并更改选择器视图:

- (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;
        }
    }
}
遗留问题: 正如我在开头所写的那样,当照片被拍摄时,它被正确地显示为接受或拒绝它。这一点现在也发生了变化。不知何故,我需要知道何时拍摄图像并将其转换回来

而且,这确实是一个令人讨厌的黑客行为,可能无法在下一次iOS更新中使用。有人知道如何以更干净的方式实施吗

更新2

这太令人讨厌了,我找到了一个更干净的解决方案,解决了我的问题,但并不是关于popover控制器中图像采集器的最初问题的答案,这不是苹果公司推荐的,而是允许的

我现在对UIImagePickerController进行了如下子类化:

@implementation QPImagePickerController

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

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscape;
}

@end

我用全屏的图像采集器代替了popover。到目前为止已在iOS7中测试。

UIImagePickerController有一个名为cameraViewTransform的属性。对此应用CGAffineTransform将变换预览图像,但不会变换捕获的图像,因此将正确捕获该图像。我遇到了与您描述的相同的问题,我通过创建相机控制器并将其放置在popover中解决了它(对于iOS7),如下所示:

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

我也在横向缩放图像,使其比其他方式更能填满取景器。在我看来,这一切都相当糟糕,但我希望在iOS7.1出现后能够将其删除。

我找到了另一种解决方案,可以处理设备旋转的情况,而UIIMagePickerView根据提供的答案显示。它还处理视图从UIOrientationAndscapeRight/UIOrientationAndscapeLeft旋转回UIOrientationGrait的情况

我创建了UIImagePickerController的一个子类:

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];
#import <UIKit/UIKit.h>

@interface PMImagePickerController : UIImagePickerController

@end
选择器fixCameraOrientation包含带一个额外案例的Journeyman代码,包装在一个检查中,以确保sourceType是相机:

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

}
这里最重要的情况是设备方向变成纵向。在这种情况下,需要重置覆盖视图。如果设备旋转,在图像选择器视图加载后调用fixCameraOrientation选择器也很重要:

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

带摄像头的iPad-不要在popover中显示。相反,在模态视图控制器中显示,就像在iPhone上一样。(至少从iOS 7开始)

我的应用程序中也有类似的情况。但是,预览在iOS7中正确旋转,而不是在iOS8中。此代码假定您有多个方向

第一件事是子类化
UIImagePickerController

从顶部开始,将
#import
添加到.m文件中

还添加一个属性以保存初始方向
@property(非原子)UIInterfaceOrientation startingOrientation
和另一个用于删除裁剪的条件
@property(非原子)BOOL didtemptoremovecroping

我们要听几个通知。
UIApplicationIDChangeStatusBarOrientation通知显然是为了监听设备旋转
AVCaptureSessionDidStartRunningNotification
在相机开始拍摄时立即调用

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationDidChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureSessionDidStart:) name:AVCaptureSessionDidStartRunningNotification object:nil];
-captureSessionDidStart:
中添加一个条件,以验证视图是否实际在屏幕上,并确保在(self.view.window&&self.sourceType==UIImagePickerControllerSourceTypeCamera)
的情况下应该显示摄像头。如果是,请设置起始方向
self.startingOrientation=[UIApplication sharedApplication].statusBarOrientation

-statusBaroOrientationDidChange:
中添加与上述相同的条件,但这次如果为true,我们将更新摄影机变换。首先,我们得到基于初始旋转的偏移旋转。在除纵向以外的方向中输入
UIImagePickerController
时,需要执行此操作

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;
}));
最后,我们将尝试从起始方向移除以90度方向呈现的黑色条。(这可能只是iOS8的问题。)更详细地说,如果我在纵向模式下输入
UIImagePickerController
,然后旋转到横向,预览的顶部和底部将出现黑色条。解决方案不是缩放,而是删除superview的剪裁。我们只需要进行一次尝试,因此首先检查是否调用了此代码。还要确保我们只在旋转后调用此代码。如果在初始方向调用它,它将无法立即工作

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

    [self findClippedSubviewInView:self.view];
}
最后在
-findClippedSu的代码中
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];
}
#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