在 iOS 7 中呈现 UIImagePickerController 的问题

Posted

技术标签:

【中文标题】在 iOS 7 中呈现 UIImagePickerController 的问题【英文标题】:Issue with presenting UIImagePickerController in iOS 7 【发布时间】:2013-10-31 11:34:56 【问题描述】:

我的应用程序仅在横向模式下运行!所以我知道UIImagePickerController 仅以纵向模式呈现,所以在 ios 6 中,我创建了 UIImagePickerController 的子类,强制 UIImagePickerController 以纵向模式打开:

@interface NonRotatingUIImagePickerController : UIImagePickerController

@end

@implementation NonRotatingUIImagePickerController

- (BOOL)shouldAutorotate 

    return NO;


@end

//presenting picker controller :

UIImagePickerController *ipc = [[NonRotatingUIImagePickerController alloc]init];
ipc.delegate = self;
[self presentViewController:ipc animated:YES completion:nil];

这在 iOS 6 中运行良好,但现在在 iOS 7 中,我的应用确实因此而崩溃:

2013-10-31 14:56:01.028 Medad[1731:60b] *** Terminating app due to
uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason:
'Supported orientations has no common orientation with the
application, and shouldAutorotate is returning YES'

如果我在部署信息中检查Portrait,这个问题可以解决:

问题是,如果我选中此选项,我的应用程序也会纵向运行,但我不想要它!

我该如何解决这个问题?

【问题讨论】:

@Mc.Lover - 你试过我的解决方案了吗? 我通过示例添加了一个可行的解决方案 【参考方案1】:

我已经对其进行了测试,发现您不应该通过目标窗口中的复选框来处理方向,如上图所示,因为它是您的整个应用程序方向,因此请选中所有框以支持所有方向。如果你想要一些不同方向的视图和一些不同的视图,那么你必须通过在 ViewController 类中的编码来处理它,方法是返回 YESNO 用于方向。

这是我的Sample。我做的。请检查。

下面的方法将处理ViewController的方向

-(BOOL)shouldAutorotate

    return YES;


-(NSUInteger)supportedInterfaceOrientations

    return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;


// Old Method
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation

    if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) 
     return NO;
    
    else 
        return YES;
    

因此,解决方案是:为UIImagePickerController 制作两个自定义类,另一个为ViewController(适用于所有视图控制器)制作两个自定义类,并将它们用于特定方向并将这些类用作UIImagePickerController 的超类以及所有ViewControllers

【讨论】:

【参考方案2】:

有一种简单的解决方案可以避免更改应用支持的方向,并使UIImagePickerController 正常工作:仅在必须呈现选择器时才返回UIInterfaceOrientationMaskAll

您可以简单地继承 UIApplication 并使用这两种方法:

- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window

    UIViewController *topController = window.rootViewController;

    if ([self hasPicker:topController])
        return UIInterfaceOrientationMaskAll;

    return [super supportedInterfaceOrientationsForWindow:window];


-(BOOL)hasPicker:(UIViewController *)controller

    BOOL hasPicker = NO;

    NSLog(@"Check Controller: %@", controller);

    if ([controller isKindOfClass:[UIImagePickerController class]])
        return YES;

    for (UIViewController *child in controller.childViewControllers) 
        hasPicker = [self hasPicker:child];

        if (hasPicker)
            return YES;
    

    return NO;

在第一种方法中,您将覆盖默认的supportedInterfaceOrientationsForWindows: 方法。每次调用该方法时,都会检查层次结构中的所有视图控制器(通过hasPicker:,一种递归方法)。如果找到 UIImagePickerController,则返回 UIInterfaceOrientationMaskAll,否则返回应用的默认设置。

我建议你的另一件事:不要继承UIImagePickerController,因为Apple 明确禁止它。相反,像我在这个例子中所做的那样使用视图控制器包含:

Landscape Picker Example

注意:示例代码仅适用于 UIImagePickerController 遏制。如果您将其子类化并通过presentViewController: 添加它,您可能需要调整hasPicker: 方法的行为。您可以做的另一件简单的事情是:向您的 UIApplication 子类添加一个实例变量,并在您显示选择器时设置它,并在您关闭时取消设置

【讨论】:

【参考方案3】:

另一种解决方案。

在每个控制器中添加,甚至添加到具有选择器的控制器:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft
        || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
    
        return YES;
    
    return NO;


- (BOOL)shouldAutorotate 
    return YES;


- (NSUInteger)supportedInterfaceOrientations 
    return UIInterfaceOrientationMaskLandscape;

将此添加到您的自定义选择器控制器:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    if (interfaceOrientation == UIInterfaceOrientationPortrait)
    
        return YES;
    

    return NO;


- (BOOL)shouldAutorotate 
    return YES;


- (NSUInteger)supportedInterfaceOrientations 
    return UIInterfaceOrientationMaskPortrait;

【讨论】:

我认为这个解决方案会为您解决问题。我更深入地研究了它。 如果这也崩溃了。你只有我提出的其他解决方案。 我终于找到了解决办法!我创建了一个自定义导航控制器并将其与主 ViewController 链接 而自定义导航控制器与选择器的关系如何?【参考方案4】:

在每个控制器中添加:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft
        || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
    
        return YES;
    
    return NO;


- (BOOL)shouldAutorotate 
    return YES;


- (NSUInteger)supportedInterfaceOrientations 
    return UIInterfaceOrientationMaskLandscape;

对于控制器,您有选择器: 仅使用纵向设计此视图。因此,它将具有与选择器相同的方向。此视图将是唯一的纵向视图,而其他视图为横向。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    if (interfaceOrientation == UIInterfaceOrientationPortrait)
    

        return YES;
    

    return NO;


- (BOOL)shouldAutorotate 

    UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

    if (orientation==UIInterfaceOrientationPortrait) 

    

    return YES;


- (NSUInteger)supportedInterfaceOrientations 
    return UIInterfaceOrientationMaskPortrait;

其他解决方案也会在具有选择器的视图中崩溃,因为它们不会返回纵向来处理选择器方向。虽然不向此视图控制器添加任何代码将使此视图以横向和纵向运行。

因此,我提出的解决方案是在横向运行所有视图,而在纵向运行这个视图。纵向显示此视图更符合设计逻辑,以使选择器具有相同的方向。

以下内容进入您的自定义选择器:

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    
        if (interfaceOrientation == UIInterfaceOrientationPortrait)
        
            return YES;
        

        return NO;
    

    - (BOOL)shouldAutorotate 
        return YES;
    

    - (NSUInteger)supportedInterfaceOrientations 
        return UIInterfaceOrientationMaskPortrait;
    

【讨论】:

除非选中肖像,否则仍然会崩溃! 答案没有崩溃你是指另一个吗? ios 7 中的选择器仅以纵向显示。你是风景。这个答案建议您将设计更改为仅包含选择器的视图的纵向。因为您也不希望视图方向与选择器方向不同。 这个答案有 3 个不同的代码。一个用于所有视图,一个用于包含选择器的视图。一个用于自定义选择器。你这样做了吗? 另一种解决方案,您将选择器放在具有纵向方向的单独视图控制器中。当您想显示选择器时,您会显示该视图,然后显示您的选择器。当用户选择时。隐藏选择器并关闭视图以返回原始视图。明白了吗?【参考方案5】:

你还应该在子类中设置:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

    return UIInterfaceOrientationLandscapeLeft ;


- (NSUInteger)supportedInterfaceOrientations 
    return UIInterfaceOrientationMaskLandscape;


- (BOOL)shouldAutorotate 
    return YES;

现在您可以从设置中删除“肖像”

[编辑] 由于 UIImagePickerController 只能以纵向显示(根据 Apple 文档),因此可以反其道而行之,启用纵向和横向方向,但将除选取器控制器之外的所有对象的方向固定为横向。我做了一个可以从here下载的小样本。

【讨论】:

您使用的是容器视图控制器吗?比如 UINavigationController 或 UITabbarController? 不,我不使用 UINavigationController 等.. 只是一个简单的 UIViewControleller 看起来 UIImagePickerController 确实不支持横向,如文档 ***.com/questions/14618546/… 中所述。你应该另谋出路。所以使用3方向,只需将上述方法添加到其他vcs中,不要子类化picker。 午餐选择器在纵向或横向模式下都没有关系!我只是不想在部署信息中检查纵向模式,因为所有视图控制器都在旋转!!!即使我仅使用代码将方向设置为横向模式 这就是重点,你检查它,然后在每个 VC(或者你创建一个抽象 VC 类)中,除了选择器(你没有子类化)你对其他 VC 说只在景观。是您想要做的相反的事情,但它会导致相同的结果。这样,选择器将以纵向正确打开,而另一个只是横向打开。【参考方案6】:

其实我有同样的问题,并以不同的方式解决它...... 实际上,这被确定为 IOS6 中的一个错误,它发生在 ImageViewController 上,它只支持纵向方向......所以我花了很多时间找到了一种解决方法......

希望这会有所帮助,所以首先...

在您的 AppDelegate.h 中添加一个属性

@property BOOL model;

然后在 AppDelegate.m 中

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    // Override point for customization after application launch.
    self.model=NO;

    return YES;

在 AppDelegate.m 中也添加这个方法

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window


    if(!self.model)
        return  UIInterfaceOrientationMaskLandscape; //or needed orientation
    else

        return UIInterfaceOrientationMaskAllButUpsideDown;



然后在您的视图控制器中呈现图像选择器之前

实现此代码...

AppDelegate *appdelegate=(AppDelegate*)[[UIApplication sharedApplication] delegate];
            appdelegate.model=YES;

然后你只需在选择图像后返回时更改值,即委托方法

AppDelegate *appdelegate=(AppDelegate*)[[UIApplication sharedApplication] delegate];
            appdelegate.model=NO;

【讨论】:

以上是关于在 iOS 7 中呈现 UIImagePickerController 的问题的主要内容,如果未能解决你的问题,请参考以下文章

更改通过 UIPopOver (iPad) 呈现的 UIImagePicker 的大小

如何模态呈现一个视图来选择 UIImagePicker sourceType?

在 iOS 中存储 UIImagePicker 选取的图像

如何在 iOS 的某些文件输入字段上获取 UIWebView 中 UIImagePicker 选择的图像?

如何在 iOS 上的 UIImagePicker 中获取实际图像框架的大小?

在 iOS8 上使用 UIImagePicker 结果 URL 和 PHAsset 从“我的照片流”加载图像