【问题标题】:Issue with presenting UIImagePickerController in iOS 7在 iOS 7 中呈现 UIImagePickerController 的问题
【发布时间】: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 - 你试过我的解决方案了吗?
  • 我通过示例添加了一个可行的解决方案

标签: ios iphone objective-c xcode ipad


【解决方案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 确实不支持横向,如文档 stackoverflow.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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-12
        • 2012-09-13
        • 1970-01-01
        • 2022-11-09
        • 1970-01-01
        • 2013-10-04
        • 2015-10-28
        • 2013-10-20
        相关资源
        最近更新 更多