iOS 8からframe
など座標を考える上で、スクリーン上で見えているOrientationの左上が原点となるようになった。
月日は流れiOS 11も出る頃なので、いい加減切りたいバージョンも増えつつある今日このごろ、
[UIWindow new]を使用するにあたって、iOS 8系でのみ発生する不具合のような挙動に直面した。
多分Swiftでも起こるのでタグ付けした。
何が起こるか
iOS 8でだけ、UIWindowを生成して表示したとき、Landscape表示しているにも関わらずPortraitで表示される。
どういう状況で起こるか
- iOS 8.xである(iOS 7.x以下、iOS 9.x以上では発生しない)
-
[UIWindow new]
でWindowを生成する - 生成したWindowは
[vc shouldAutorotate] == NO
となるViewController
をrootViewController
に持つ - 生成したWindowの
frame
をフルスクリーンにしようと[UIScreen mainScreen].bounds
の値を使う - Landscape状態でWindowを生成・表示する
以下は要点を抽出したコード。
// SampleViewController.h
@interface SampleViewController : UIViewController
@end
// SampleViewController.m
@implementation SampleViewController
- (BOOL)shouldAutoRotate {
return NO;
}
@end
// ViewController.m
@interface ViewController ()
@property (nonatomic) UIWindow *w;
@end
@implementation ViewController
- (IBACtion)openWindow:(UIButton*)sender {
UIWindow *w = [UIWindow new];
w.frame = [UIScreen mainScreen].bounds;
w.rootViewController = [SampleViewController new];
self.w = w;
[self.w makeKeyAndVisible];
}
@end
これが
こうなる
iOS 8だけ、UIScreenの原点と生成したWindowの原点が異なっている。
- UIScreenは見えているスクリーンの左上を原点としている
-
[UIWindow new]
によって生成されたUIWindow
はPortrait
状態の左上を原点としている
HACKに解決
shouldAutoRotate
がYES
なUIViewControllerを持たせた上でmakeKeyAndVisible
かけたら上手くいくんじゃね?という発想のもと、以下のようにしたところ上手くいった。
- (IBACtion)openWindow:(UIButton*)sender {
UIWindow *w = [UIWindow new];
w.frame = [UIScreen mainScreen].bounds;
// HACK: iOS 8系にてShouldAutoRotate == NO のViewControllerを
// rootViewControllerに持ってmakeKeyAndVisibleを実行すると
// アプリケーションのInterfaceOrientationに関わらず
// InterfaceOrientationPortrait状態のWindowが表示されてしまう
// iOS 9以降では空のUIViewControllerを持たせる必要はなく、
// 表示したいViewControllerを持たせて構わない
w.rootViewController = [UIViewController];
self.w = w;
[self.w makeKeyAndVisible];
// HACK: iOS 8系にてShouldAutoRotate == NO のViewControllerを
// rootViewControllerに持ってmakeKeyAndVisibleを実行すると
// アプリケーションのInterfaceOrientationに関わらず
// InterfaceOrientationPortrait状態のWindowが表示されてしまう
// よって空のViewControllerを持たせてmakeKeyAndVisibleを実行した後に
// ViewControllerを差し替える
w.rootViewController = [SampleViewController new];
}
直前まで表示されていたWindowのInterfaceOrientationを元に、表示したいWindowにtransformかけるしかないのか…?という悩みから解決されて最高に気分がいい。
-
swift - iOS 8 - UIWindow Orientation Is Always Portrait - Stack Overflow
- 読んだ時別件かなと思ったけど、解決した今、たしかにこの追記がベストな回答だと理解した