允许 iPhone 6 Plus 横向,但不允许其他 iPhones

Allow landscape for iPhone 6 Plus but not other iPhones

在我的通用应用程序中,我目前覆盖 window 的根视图控制器中的 supportedInterfaceOrientations 以定义允许的方向。到目前为止,该决定是基于设备的用户界面习惯用法:

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

现在我想更改此设置,以便我也可以支持 iPhone 6 Plus 的景观,但不支持其他 iPhones。我可以想象一两个解决方案,但这些都相当脆弱,当 Apple 开始制造新设备时可能会崩溃。

在理想情况下,我想将上述方法更改为类似于以下代码段,其中决定基于设备的 用户界面大小 class而不是用户界面惯用语:

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

UIKit 中的某个地方是否有类似这种神奇的 landscapeSizeClass 方法?我浏览了各种 class 参考资料和指南,但没有找到任何有用的东西。或者有人可以提出一个同样通用且面向未来的不同解决方案吗?

请注意,我的应用程序以编程方式创建其 UI,因此完全基于情节提要的解决方案已经过时了。此外,我的应用程序仍需要支持 iOS 7,因此我不能只更改所有内容以使用大小 classes。不过,我 可以 做的是在使用简单的 iOS 8 个 API 之前进行运行时检查。

缺少官方 Apple 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;
  }
}

该代码段简单地假设尺寸大于半任意选择尺寸的屏幕适合旋转。 Semi-任意,因为 400x700 的阈值包括 iPhone 6 Plus,但不包括 iPhone 6.

虽然这个解决方案相当简单,但我非常喜欢它因为它不够复杂。我真的不需要准确区分设备,所以任何聪明的解决方案,例如 中的解决方案,对我来说都太过分了。

我宁愿使用宏来发现(出于可读性原因),例如:

#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) { ... }
- (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);
    }
}

Fwiw,相当于 Swift 1.2 中的

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