复杂的多设备方向处理
Complex Multi-Device Orientation Handling
我在 iPads 和 iPhones 上都有一个通用应用程序 运行。该应用程序以一个 .xib 文件开始,该文件内置于界面构建器中,充当启动图像。应用启动后,它会根据应用委托中设置的设备尺寸切换到适当的视图控制器:
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
if (screenSize.height <= 568.0f) {
// iPhone 4, 4S, 5, 5C, 5S, SE
self.viewController = [[iPhoneSmallViewController alloc] init];
} else {
// All other iPhones
self.viewController = [[iPhoneLargeViewController alloc] init];
}
} else {
// All iPad models
self.viewController = [[iPadViewController alloc] init];
}
iPad 视图控制器支持所有界面方向(在应用 targets/main 设置页面中设置),但在 iPhones 上我只允许在视图控制器中限制纵向模式:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
}
这个方法有两个问题:
- 如果 iPhone 水平放置,应用程序仍会以纵向模式加载(根据限制,这很好),但所有测量值在初始化时都是横向的。 UI 元素在侧面突出,因为它们是为横向视图测量的,但放置在纵向视图上。
我使用 window 的大小通过在 ViewDidLoad 方法中初始化以下变量来设置视图内的所有内容:
windowSize = [[UIScreen mainScreen] bounds].size;
Tt 给我横向尺寸 phone 水平放置,即使横向模式是不允许的。
- 如果应用程序最初加载横向尺寸,我在应用程序委托中对屏幕尺寸的所有排序都将关闭,因为我通过测量屏幕宽度来识别 iPhone 型号,这仅适用于纵向模式。
问题:有没有人有办法优雅而简单地处理这个复杂的问题?
一些附加信息:我使用 Xcode 10,一直支持 iOS9 并在 Objective C.
中以编程方式执行所有操作
p.s:我认为这种方法以前有效,但在 iOS 12 中不再适用。但我可能错了...
编辑:我提供了一张我想要完成的图片,所有帮助将不胜感激。正如我所说,这以前有效(该应用程序很旧),但在最近的 iOS 版本中,错误越来越多,迫切需要清理,这正是我需要帮助的地方。
可能会解决我的问题的一件事是,如果我可以根据 launchScreen.xib 中的设备类型以某种方式限制界面方向,因为我相信这就是导致 iPhones 上的错误行为的原因.
也许这个 SO 会有所帮助,
他们正在检测设备方向然后旋转视图,看第一个答案:
UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
此处介绍了一种更好的检测设备的方法:
iOS detect if user is on an iPad
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
return YES; /* Device is iPad */
}
我已经试验了好几天了,并找到了解决方案。虽然这可能不是最优雅的方法,所以如果有人有更好的解决方案,请随时post。
允许 info.plist 中的所有界面方向很重要,因为我无法根据 launchScreen.xib 中的设备大小限制它们。
创建同时支持 iPad 和 iPhones 的通用启动屏幕。因为在info.plist中允许所有界面方向,所以这将没有限制。
下面是我在应用委托中的当前方法。这不是识别较小的 iPhones 的最佳方法(出于某些原因我需要它...:),但由于尺寸差异,这种方法效果很好。
此时phone可以在info.plist中设置的四种界面方向中的任何一种,但是因为只有小手机才有320的宽度所以很容易抓到:
// Get screen size
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
// Determine device based on screen dimensions
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
if ( (screenSize.height == 320.0f) || (screenSize.width == 320.0f) ){
// iPhone 4, 4S, 5, 5C, 5S, SE
self.viewController = [[iPhoneSmallViewController alloc] init];
} else {
// iPhone 6, 6S, 6P, 6SP, 7, 7P, 8, 8P X, XS, XM, XR
self.viewController = [[iPhoneLargeViewController alloc] init]; //Same as previous
}
} else {
// All iPad models
self.viewController = [[iPadViewController alloc] init];
}
- 限制 iPhone 视图控制器中的界面方向(所有其他视图控制器将继承我们在 info.plist 中设置的)。
这样做:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskPortrait);
}
- 为了使上面的方法起作用,我们还需要做另一个技巧。当 window 第一次加载时,它不会考虑我们添加到视图控制器的限制。这意味着,如果我们在 viewDidLoad 方法中进行设置,如果设备水平放置(即使不允许这种方向),我们将收到横向屏幕尺寸。一旦 viewDidLoad 方法结束,将应用限制。
因此,为了防止错误行为,您需要创建一个单独的方法来进行设置(例如 postViewDidLoad),并在真正的 viewDidLoad 完成后调用它:
- (void) viewDidLoad
{
[super viewDidLoad];
[self performSelector:@selector(postViewDidLoad) withObject:nil afterDelay:0.0f];
}
在此方法中,您将根据您在 supportedInterfaceOrientations 方法中设置的限制访问实际屏幕尺寸。
基本上就是这样。如果您有多个视图,每个视图都有不同的限制,只需按照每个视图中的步骤 4 和 5 正确设置您的工作流程。
我在 iPads 和 iPhones 上都有一个通用应用程序 运行。该应用程序以一个 .xib 文件开始,该文件内置于界面构建器中,充当启动图像。应用启动后,它会根据应用委托中设置的设备尺寸切换到适当的视图控制器:
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
if (screenSize.height <= 568.0f) {
// iPhone 4, 4S, 5, 5C, 5S, SE
self.viewController = [[iPhoneSmallViewController alloc] init];
} else {
// All other iPhones
self.viewController = [[iPhoneLargeViewController alloc] init];
}
} else {
// All iPad models
self.viewController = [[iPadViewController alloc] init];
}
iPad 视图控制器支持所有界面方向(在应用 targets/main 设置页面中设置),但在 iPhones 上我只允许在视图控制器中限制纵向模式:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
}
这个方法有两个问题:
- 如果 iPhone 水平放置,应用程序仍会以纵向模式加载(根据限制,这很好),但所有测量值在初始化时都是横向的。 UI 元素在侧面突出,因为它们是为横向视图测量的,但放置在纵向视图上。
我使用 window 的大小通过在 ViewDidLoad 方法中初始化以下变量来设置视图内的所有内容:
windowSize = [[UIScreen mainScreen] bounds].size;
Tt 给我横向尺寸 phone 水平放置,即使横向模式是不允许的。
- 如果应用程序最初加载横向尺寸,我在应用程序委托中对屏幕尺寸的所有排序都将关闭,因为我通过测量屏幕宽度来识别 iPhone 型号,这仅适用于纵向模式。
问题:有没有人有办法优雅而简单地处理这个复杂的问题?
一些附加信息:我使用 Xcode 10,一直支持 iOS9 并在 Objective C.
中以编程方式执行所有操作p.s:我认为这种方法以前有效,但在 iOS 12 中不再适用。但我可能错了...
编辑:我提供了一张我想要完成的图片,所有帮助将不胜感激。正如我所说,这以前有效(该应用程序很旧),但在最近的 iOS 版本中,错误越来越多,迫切需要清理,这正是我需要帮助的地方。
可能会解决我的问题的一件事是,如果我可以根据 launchScreen.xib 中的设备类型以某种方式限制界面方向,因为我相信这就是导致 iPhones 上的错误行为的原因.
也许这个 SO 会有所帮助, 他们正在检测设备方向然后旋转视图,看第一个答案:
UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
此处介绍了一种更好的检测设备的方法: iOS detect if user is on an iPad
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
return YES; /* Device is iPad */
}
我已经试验了好几天了,并找到了解决方案。虽然这可能不是最优雅的方法,所以如果有人有更好的解决方案,请随时post。
允许 info.plist 中的所有界面方向很重要,因为我无法根据 launchScreen.xib 中的设备大小限制它们。
创建同时支持 iPad 和 iPhones 的通用启动屏幕。因为在info.plist中允许所有界面方向,所以这将没有限制。
下面是我在应用委托中的当前方法。这不是识别较小的 iPhones 的最佳方法(出于某些原因我需要它...:),但由于尺寸差异,这种方法效果很好。
此时phone可以在info.plist中设置的四种界面方向中的任何一种,但是因为只有小手机才有320的宽度所以很容易抓到:
// Get screen size
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
// Determine device based on screen dimensions
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
if ( (screenSize.height == 320.0f) || (screenSize.width == 320.0f) ){
// iPhone 4, 4S, 5, 5C, 5S, SE
self.viewController = [[iPhoneSmallViewController alloc] init];
} else {
// iPhone 6, 6S, 6P, 6SP, 7, 7P, 8, 8P X, XS, XM, XR
self.viewController = [[iPhoneLargeViewController alloc] init]; //Same as previous
}
} else {
// All iPad models
self.viewController = [[iPadViewController alloc] init];
}
- 限制 iPhone 视图控制器中的界面方向(所有其他视图控制器将继承我们在 info.plist 中设置的)。
这样做:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskPortrait);
}
- 为了使上面的方法起作用,我们还需要做另一个技巧。当 window 第一次加载时,它不会考虑我们添加到视图控制器的限制。这意味着,如果我们在 viewDidLoad 方法中进行设置,如果设备水平放置(即使不允许这种方向),我们将收到横向屏幕尺寸。一旦 viewDidLoad 方法结束,将应用限制。
因此,为了防止错误行为,您需要创建一个单独的方法来进行设置(例如 postViewDidLoad),并在真正的 viewDidLoad 完成后调用它:
- (void) viewDidLoad
{
[super viewDidLoad];
[self performSelector:@selector(postViewDidLoad) withObject:nil afterDelay:0.0f];
}
在此方法中,您将根据您在 supportedInterfaceOrientations 方法中设置的限制访问实际屏幕尺寸。
基本上就是这样。如果您有多个视图,每个视图都有不同的限制,只需按照每个视图中的步骤 4 和 5 正确设置您的工作流程。