只允许iPhone 6 Plus支持横屏模式,而不支持其他iPhone机型

6

在我的通用应用中,我目前在窗口的根视图控制器中覆盖了supportedInterfaceOrientations来定义允许的方向。直到现在,决策都是基于设备的用户界面风格:

- (NSUInteger) supportedInterfaceOrientations
{
  if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
    return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
  else
    return UIInterfaceOrientationMaskAll;
}

现在我想修改这个问题,以便我还可以支持iPhone 6 Plus的横屏显示,但不支持其他iPhone设备。我可以想象出一两个解决方案,但这些解决方案都比较脆弱,并且可能会在苹果推出新设备时失效。

在理想情况下,我希望将上述方法更改为以下片段,其中决策基于设备的用户界面大小类而不是用户界面风格:

- (NSUInteger) supportedInterfaceOrientations
{
  // Note the hypothetical UIDevice method "landscapeSizeClass"
  if ([[UIDevice currentDevice] landscapeSizeClass] == UIUserInterfaceSizeClassCompact)
    return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
  else
    return UIInterfaceOrientationMaskAll;
}

有没有类似于UIKit中神奇的“landscapeSizeClass”方法?我在各种类引用和指南中都找了一些,但是没有找到有用的东西。或者有人可以建议一个不同的解决方案,它同样具有通用性和未来性吗?
请注意,我的应用程序是通过编程方式创建其UI的,因此纯粹基于故事板的解决方案是行不通的。此外,我的应用程序仍然需要支持iOS 7,因此我不能只是改变所有内容以使用大小类。但是,我可以在使用简单的iOS 8 API之前进行运行时检查。

请自行设计您自己的尺寸类替代方案,例如在这里我的回答中提供了一个示例:http://stackoverflow.com/questions/28423001/how-to-differ-between-ipad-mini-and-ipad-air/28424930#28424930 - Jef
我想到了一个类似的东西,虽然比你做的简单得多。我会在一两天内发布我的解决方案,但是让我先看看是否有人能够变魔术 :-) - herzbube
BOOL allowLandscape = ( ( [UIScreen mainScreen].bounds.size.height > 800 ) || ( [UIScreen mainScreen].bounds.size.width > 800 ) ) ; 那么这样怎么样? - Jef
4个回答

2

出于可读性的原因,我宁愿使用宏来发现这一点,例如:

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
#define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT))
#define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT))
#define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

然后:

    - (NSUInteger) supportedInterfaceOrientations
    {
      if (IS_IPAD || IS_IPHONE_6P)
      {
        return UIInterfaceOrientationMaskAll;  
      }
      else
      {
        return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
      }
    }

编辑:

可能最好只有一个宏定义,而不是IS_IPHONE_6P和IS_IPAD两个宏定义:

#define IS_LANDSCAPE_REGULAR_SIZE (SCREEN_MAX_LENGTH >= 736.0)

然后:

if (IS_LANDSCAPE_REGULAR_SIZE) { ... }

这就是所谓的“脆弱”解决方案。那么,如果iPhone 6s+有一个740像素的屏幕又怎样呢? - gnasher729
这就是为什么我在修改的解决方案中设置了“SCREEN_MAX_LENGTH >= 736.0”。但无论如何,这两种方法都应该是暂时的解决方案,直到苹果提供更好的方法。 - fray88

1

由于缺乏官方的苹果API,这是我想出的解决方法:

- (NSUInteger) supportedInterfaceOrientations
{
  if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
  {
    // iPhone 5S and below: 320x480
    // iPhone 6: 375x667
    // iPhone 6 Plus: 414x736
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    // The way how UIScreen reports its bounds has changed in iOS 8.
    // Using MIN() and MAX() makes this code work for all iOS versions.
    CGFloat smallerDimension = MIN(screenSize.width, screenSize.height);
    CGFloat largerDimension = MAX(screenSize.width, screenSize.height);
    if (smallerDimension >= 400 && largerDimension >= 700)
      return UIInterfaceOrientationMaskAll;
    else
      return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
  }
  else
  {
    // Don't need to examine screen dimensions on iPad
    return UIInterfaceOrientationMaskAll;
  }
}

这段代码假设屏幕尺寸大于一个半随机选择的尺寸就适合旋转。所谓半随机,因为400x700的阈值包括了iPhone 6 Plus,但排除了iPhone 6。
虽然这个解决方案相当简单,但我喜欢它正是因为它缺乏复杂性。我不需要准确区分设备,所以像Jef's answer中的聪明解决方案对我的目的来说过于复杂。

这基本上是我的第二条评论,完全正确的伙计。只需删除userUdiom的内容,因为它已经过时且不必要,iPad会自动落在正确的一侧。 - Jef
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - herzbube
哎呀,我的错。我是从去年晚些时候介绍大小类别的WWDC会议上得到这个信息的,也许工程师说它很快就会被弃用了,我混淆了。随着6+支持UISplitViewController、UIPopoverController、从Springboard横向启动等功能,它已经失去了任何用处。你真的认为未来会有比某些iPhone更小的iPad吗?那将非常有趣... - Jef

0
- (NSUInteger) supportedInterfaceOrientations {
    if (self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular ||
        self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) {
        return UIInterfaceOrientationMaskAll;
    } else {
        return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
    }
}

更新: 之前的方法不起作用,这里提供另一种解决方案

- (NSUInteger) supportedInterfaceOrientations {
    if (self.traitCollection.displayScale == 3.0 || (self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular &&
        self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular)) {
        return UIInterfaceOrientationMaskAll;
    } else {
        return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
    }
}

那不起作用。例如,您的解决方案即使对于像iPhone 4S这样的小设备也返回UIInterfaceOrientationMaskAll,因为它们具有垂直大小类UIUserInterfaceSizeClassRegular。如果您试图想出一种解决方法,请忘记它,它不会起作用:iPhone 6+在纵向方向上的大小类与iPhone 4S的大小类相同,因此只要它们处于纵向方向上,这两个设备就几乎无法区分。 - herzbube
我并不信服。displayScale 可能暂时可行,但一旦苹果发布下一代 iPhone(很可能所有的 displayScale 都为 3.0),这个解决方案很可能会再次出现问题。在我看来,一个可靠的解决方案必须以某种方式能够测量横向屏幕尺寸,而与当前设备方向无关。无论是以点(我的当前解决方案)还是以某种抽象形式(例如大小类)进行测量都是次要的。 - herzbube

0

顺便提一下,在Swift 1.2中等价于herzbube的答案

override func supportedInterfaceOrientations() -> Int {
    if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
        let size = self.view.bounds.size
        let smallerDimension = min(size.width, size.height)
        let largerDimension = max(size.width, size.height)
        if smallerDimension >= 400 && largerDimension >= 700 {
            return Int(UIInterfaceOrientationMask.All.rawValue)
        } else {
            return Int(UIInterfaceOrientationMask.Portrait.rawValue)
        }
    } else {
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }
}

虽然个人更喜欢以下的风格:

override func supportedInterfaceOrientations() -> Int {

    if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }

    let size = self.view.bounds.size
    let smallerDimension = min(size.width, size.height)
    let largerDimension = max(size.width, size.height)

    return smallerDimension >= 400 && largerDimension >= 700 ?
        Int(UIInterfaceOrientationMask.All.rawValue) :
        Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接