Allow landscape for iPhone 6 Plus but not other iPhones

℡╲_俬逩灬. 提交于 2019-12-09 17:39:05

问题


In my universal app I currently override supportedInterfaceOrientations in the window's root view controller to define the orientations that are allowed. Up until now the decision was based on the device's user interface idiom:

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

Now I would like to change this so that I can also support landscape for the iPhone 6 Plus, but NOT for other iPhones. I can image one or two solutions, but these are all rather brittle and will probably break when Apple starts to make new devices.

In an ideal world I would like to change the above method to look like the following snippet, where the decision is based on the device's user interface size class instead of the user interface idiom:

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

Is there something like this magical landscapeSizeClass method somewhere in UIKit? I have looked around a bit in various class references and guides, but didn't find anything useful. Or can someone suggest a different solution that is similarly generic and future-proof?

Note that my app creates its UI programmatically, so purely storyboard-based solutions are out. Also my app still needs to support iOS 7 so I can't just change everything to use size classes. What I can do, though, is to make runtime checks before I use simple iOS 8 APIs.


回答1:


I will rather use macros to discover that (for readability reasons), with something like:

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

And then:

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

Edited:

It may better to have this one macro instead IS_IPHONE_6P and IS_IPAD:

#define IS_LANDSCAPE_REGULAR_SIZE (SCREEN_MAX_LENGTH >= 736.0)

And then:

if (IS_LANDSCAPE_REGULAR_SIZE) { ... }



回答2:


Lacking an official Apple API, this is the workaround that I've come up with:

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

The snippet simply assumes that a screen with dimensions above a semi-arbitrarily chosen size is suitable for rotation. Semi-arbitrarily, because a threshold of 400x700 includes the iPhone 6 Plus, but excludes the iPhone 6.

Although this solution is rather simple, I like it exactly because of its lack of sophistication. I don't really need to distinguish exactly between devices, so any clever solutions such as the one in Jef's answer are overkill for my purposes.




回答3:


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

Update: Previous is not working so here is different solution

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



回答4:


Fwiw, the equivalent of herzbube's answer in 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)
    }
}

though personally I prefer the following style:

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


来源:https://stackoverflow.com/questions/28529012/allow-landscape-for-iphone-6-plus-but-not-other-iphones

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!