UIWindow 方向问题(两个 UIWindows 和横向模式)
UIWindow orientation issues (two UIWindows and landscape mode)
我知道这看起来是个大问题,但事实并非如此,所以请不要害怕阅读它。主要是我在解释这些东西是如何工作的。
我的应用程序中有两个 UIWindow
。第一个是主 window,默认情况下由应用程序创建。第二个称为 modalWindow
,也是在应用程序委托中创建的。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.modalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.modalWindow.windowLevel = UIWindowLevelStatusBar;
//Other stuff I need
//....
return YES;
}
我的大部分应用程序都是纵向的,但有一个视图控制器,用户可以在其中切换到横向。我正在通过以下方式收听景观变化:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
这很好用,在 orientationChanged
方法中我展示了横向视图控制器。此时一切都很好。如果我旋转回纵向,我会再次触发 orientationChanged
,此时我关闭横向视图控制器。
现在让我们解释一下第二个 window 是如何发挥作用的。在横向模式下,有一个动作(只需按下按钮)在第二个 window(modalWindow
)上呈现一个新的视图控制器。好的,让我们解释一下。
应用委托有两个方法,如下所示:
- (void)presentActivityOnModalWindow:(UIViewController *)viewController
{
self.modalWindow.rootViewController = viewController;
self.modalWindow.hidden = NO;
}
- (void)modalTransitionFinished:(NSNotification *)notif
{
self.modalWindow.hidden = YES;
self.modalWindow.rootViewController = nil;
}
我通过 [[[UIApplication sharedApplication] delegate] performSelector....]
调用 presentActivityOnModalWindow
。我知道这不是最佳做法,但效果很好。至于解雇我使用NSNotificationCenter
到post有关解雇的通知。 modalWindow
上显示的视图控制器仅支持纵向模式。它在 shouldAutorotate
中返回 YES
,在 supportedInterfaceOrientations
中返回 UIInterfaceOrientationMaskPortrait
。
好的,解释了很多,但现在我们要解决问题了。当我旋转到横向时,弹出 modalWindow,关闭模态 window 并旋转回纵向我的主要 window 仍然处于横向模式,一切看起来都是灾难性的。
我尝试向 window
和 modalWindow
添加一个观察者,并在 frame
和 bounds
中记录更改,结果如下:
Did finish launching:
window frame {{0, 0}, {320, 568}}
window bounds {{0, 0}, {320, 568}}
modalWindow frame {{0, 0}, {320, 568}}
modalWindow bounds {{0, 0}, {320, 568}}
Rotate to landscape:
window frame {{0, 0}, {568, 320}}
Open activity in landscape:
modalWindow frame {{0, 0}, {320, 568}}
modalWindow frame {{0, 0}, {320, 568}}
Dismiss activity:
none
Rotate back to portrait:
none
所以当我们回到纵向模式时,我的 window
似乎没有恢复到正常画面。 如何解决这个问题? 如果我需要提供更多详细信息,请随时询问。
您正在创建 2 windows,Apple 建议不要这样做。有多少显示设备,应用程序就应该有多少 windows。(SEE UIWindow reference )
我建议使用 2 个视图,"drawing" 根据方向将所有内容都放在这些视图上。然后在显示另一个视图时隐藏一个视图。
或者,您可以只使用 1 个视图并在方向更改时进行调整。这样做的难易程度取决于所显示信息的类型。
方向变化最好由 AppDelegate 代码检测。
这是我用来检测方向变化然后检查 window 的新尺寸的代码示例。
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
{
//other stuff from rotate:
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect appFrame = [[UIScreen mainScreen ]applicationFrame];//using frame so status bar is not part of calculations.
if (orientation == UIInterfaceOrientationLandscapeRight
||
orientation == UIInterfaceOrientationLandscapeLeft
)
{
self.currentAppScreenWidth = appFrame.size.height;
self.currentAppScreenHeight = appFrame.size.width;
[YOURapp reArrangeSubViews_and_Layouts: appFrame];//Something like this - maybe.
}
else
{
self.currentAppScreenWidth = appFrame.size.width;
self.currentAppScreenHeight = appFrame.size.height;
[YOURapp reArrangeSubViews_and_Layouts: appFrame];//Something like this - maybe.
}
}
希望对您有所帮助。
另一件事。如果您使用不同的布局显示相同的信息,那么您应该能够使用 Xcode 工具对其进行布局,以适当的方式适应方向。如果某些事情仍然不完美,请尝试使用代码进行调整。
如果您要显示完全不同的信息,2 视图方法可能是最简单的。
[如果上述解决方案不适合您,也许可以提供更多有关两个屏幕上显示的数据差异的信息。
干杯。]
系统只会处理您 keyWindow
的旋转。如果您有其他 windows,则必须自己处理旋转。
我也认为模态控制器是可行的方法。但是,如果您真的想处理旋转,请查看其他 "custom windows" 库如何处理旋转。警报视图就是一个很好的例子:
https://github.com/search?o=desc&q=uialertview&s=stars&type=Repositories&utf8=✓
Apple 不鼓励以这种方式使用 windows。最好使用模态显示的 UIViewController
而不是
self.modalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
模态呈现 UIViewController
是从 UIViewController
实例使用
完成的
[self presentViewController:<#(UIViewController *)#> animated:<#(BOOL)#> completion:<#^(void)completion#>]
我知道这看起来是个大问题,但事实并非如此,所以请不要害怕阅读它。主要是我在解释这些东西是如何工作的。
我的应用程序中有两个 UIWindow
。第一个是主 window,默认情况下由应用程序创建。第二个称为 modalWindow
,也是在应用程序委托中创建的。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.modalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.modalWindow.windowLevel = UIWindowLevelStatusBar;
//Other stuff I need
//....
return YES;
}
我的大部分应用程序都是纵向的,但有一个视图控制器,用户可以在其中切换到横向。我正在通过以下方式收听景观变化:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
这很好用,在 orientationChanged
方法中我展示了横向视图控制器。此时一切都很好。如果我旋转回纵向,我会再次触发 orientationChanged
,此时我关闭横向视图控制器。
现在让我们解释一下第二个 window 是如何发挥作用的。在横向模式下,有一个动作(只需按下按钮)在第二个 window(modalWindow
)上呈现一个新的视图控制器。好的,让我们解释一下。
应用委托有两个方法,如下所示:
- (void)presentActivityOnModalWindow:(UIViewController *)viewController
{
self.modalWindow.rootViewController = viewController;
self.modalWindow.hidden = NO;
}
- (void)modalTransitionFinished:(NSNotification *)notif
{
self.modalWindow.hidden = YES;
self.modalWindow.rootViewController = nil;
}
我通过 [[[UIApplication sharedApplication] delegate] performSelector....]
调用 presentActivityOnModalWindow
。我知道这不是最佳做法,但效果很好。至于解雇我使用NSNotificationCenter
到post有关解雇的通知。 modalWindow
上显示的视图控制器仅支持纵向模式。它在 shouldAutorotate
中返回 YES
,在 supportedInterfaceOrientations
中返回 UIInterfaceOrientationMaskPortrait
。
好的,解释了很多,但现在我们要解决问题了。当我旋转到横向时,弹出 modalWindow,关闭模态 window 并旋转回纵向我的主要 window 仍然处于横向模式,一切看起来都是灾难性的。
我尝试向 window
和 modalWindow
添加一个观察者,并在 frame
和 bounds
中记录更改,结果如下:
Did finish launching:
window frame {{0, 0}, {320, 568}}
window bounds {{0, 0}, {320, 568}}
modalWindow frame {{0, 0}, {320, 568}}
modalWindow bounds {{0, 0}, {320, 568}}
Rotate to landscape:
window frame {{0, 0}, {568, 320}}
Open activity in landscape:
modalWindow frame {{0, 0}, {320, 568}}
modalWindow frame {{0, 0}, {320, 568}}
Dismiss activity:
none
Rotate back to portrait:
none
所以当我们回到纵向模式时,我的 window
似乎没有恢复到正常画面。 如何解决这个问题? 如果我需要提供更多详细信息,请随时询问。
您正在创建 2 windows,Apple 建议不要这样做。有多少显示设备,应用程序就应该有多少 windows。(SEE UIWindow reference )
我建议使用 2 个视图,"drawing" 根据方向将所有内容都放在这些视图上。然后在显示另一个视图时隐藏一个视图。
或者,您可以只使用 1 个视图并在方向更改时进行调整。这样做的难易程度取决于所显示信息的类型。 方向变化最好由 AppDelegate 代码检测。
这是我用来检测方向变化然后检查 window 的新尺寸的代码示例。
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
{
//other stuff from rotate:
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect appFrame = [[UIScreen mainScreen ]applicationFrame];//using frame so status bar is not part of calculations.
if (orientation == UIInterfaceOrientationLandscapeRight
||
orientation == UIInterfaceOrientationLandscapeLeft
)
{
self.currentAppScreenWidth = appFrame.size.height;
self.currentAppScreenHeight = appFrame.size.width;
[YOURapp reArrangeSubViews_and_Layouts: appFrame];//Something like this - maybe.
}
else
{
self.currentAppScreenWidth = appFrame.size.width;
self.currentAppScreenHeight = appFrame.size.height;
[YOURapp reArrangeSubViews_and_Layouts: appFrame];//Something like this - maybe.
}
}
希望对您有所帮助。 另一件事。如果您使用不同的布局显示相同的信息,那么您应该能够使用 Xcode 工具对其进行布局,以适当的方式适应方向。如果某些事情仍然不完美,请尝试使用代码进行调整。 如果您要显示完全不同的信息,2 视图方法可能是最简单的。
[如果上述解决方案不适合您,也许可以提供更多有关两个屏幕上显示的数据差异的信息。 干杯。]
系统只会处理您 keyWindow
的旋转。如果您有其他 windows,则必须自己处理旋转。
我也认为模态控制器是可行的方法。但是,如果您真的想处理旋转,请查看其他 "custom windows" 库如何处理旋转。警报视图就是一个很好的例子:
https://github.com/search?o=desc&q=uialertview&s=stars&type=Repositories&utf8=✓
Apple 不鼓励以这种方式使用 windows。最好使用模态显示的 UIViewController
而不是
self.modalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
模态呈现 UIViewController
是从 UIViewController
实例使用
[self presentViewController:<#(UIViewController *)#> animated:<#(BOOL)#> completion:<#^(void)completion#>]