允许 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)
}
在我的通用应用程序中,我目前覆盖 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)
}