web-dev-qa-db-ja.com

iOS8ではカスタムUIWindowsが正しく回転しません

アプリケーションをランドスケープモードにして、次のコードを実行します。

UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
toastWindow.hidden = NO;
toastWindow.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:0.5f];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [toastWindow removeFromSuperview];
});

IOS 7では、画面全体の上に透明な青いオーバーレイが表示され、5秒後に消えます。 iOS 8では、画面の半分強をカバーする透明な青いオーバーレイが表示されます

device screenshot

これは明らかに変更と関係がありますAppleはiOS8で行われ、画面座標はデバイス指向ではなくインターフェイス指向になりましたが、本当の場合Appleランドスケープモードとローテーションで無数のバグを残したようです。

デバイスの向きが横向きであるかどうかを確認し、メイン画面の境界の幅と高さを反転させることでこれを「修正」できますが、Appleがすべてを変更すると、ひどいハックが壊れそうです再びiOS9で。

CGRect frame = [[UIScreen mainScreen] bounds];

if (UIInterfaceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
    frame.size.width = frame.size.height;
    frame.size.height = [[UIScreen mainScreen] bounds].size.width;
}

UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:frame];
toastWindow.hidden = NO;
toastWindow.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:0.5f];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [toastWindow removeFromSuperview];
});

誰かがこの問題を経験していて、より良い、より脆弱でない解決策に出くわしたことがありますか?

EDIT: UIViewを使用してキーウィンドウに追加できることはわかっていますが、ステータスバーの上に何かを配置したいと思います。

15
Reid Main

「修正」は、テキストやその他のサブビューが適切な方向で表示されるように実際にはウィンドウを回転させないという点で、別の理由で優れていません。つまり、ウィンドウを他のサブビューで拡張したい場合、それらの方向は正しくありません。

.。

IOS8では、ウィンドウのrootViewControllerを設定する必要があり、そのrootViewControllerは「shouldAutoRotate」および「supportedInterfaceOrientations」から適切な値を返す必要があります。これについては、次の場所に詳細があります: https://devforums.Apple.com/message/1050398#1050398

ウィンドウにrootViewControllerがない場合は、ウィンドウが自動回転しないようにフレームワークに効果的に伝えています。 iOS7では、フレームワークがとにかくその作業を行っていなかったため、これは違いを生みませんでした。 iOS8では、フレームワークが回転を処理しており、ウィンドウの境界を制限するときに、要求されたとおりに(nil rootViewControllerを使用して)実行していると見なします。

これを試して:

@interface MyRootViewController : UIViewController
@end

@implementation MyRootViewController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

- (BOOL)shouldAutorotate
{
    return YES;
}

@end

次に、インスタンス化された後、そのrootViewControllerをウィンドウに追加します。

UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
toastWindow.rootViewController = [[MyRootViewController alloc]init];
26
Rich Waters

UICoordinateSpaceを変換する必要があると思います。

IPhone 6 Plusでは、アプリはすでに横向きで起動できるようになりました。これは、1つの画面を除いて、ほとんどのアプリで縦向きしかサポートしていないため、作業中のアプリケーションを台無しにしました(つまり、plistで横向きをサポートする必要がありました)。

これを修正したコードは次のとおりです。

self.window = [[UIWindow alloc] initWithFrame:[self screenBounds]];

次のコードで境界を計算します。

- (CGRect)screenBounds
{
    CGRect bounds = [UIScreen mainScreen].bounds;
    if ([[UIScreen mainScreen] respondsToSelector:@selector(fixedCoordinateSpace)]) {
        id<UICoordinateSpace> currentCoordSpace = [[UIScreen mainScreen] coordinateSpace];
        id<UICoordinateSpace> portraitCoordSpace = [[UIScreen mainScreen] fixedCoordinateSpace];
        bounds = [portraitCoordSpace convertRect:[[UIScreen mainScreen] bounds] fromCoordinateSpace:currentCoordSpace];
    }
    return bounds;
}

うまくいけば、これはあなたを正しい方向に導くでしょう。

3
runmad

IOS 7以前では、UIWindowの座標系は回転しませんでした。 iOS8ではそうです。 [[UIScreen mainScreen] bounds]から提供されたフレームは回転を考慮していないと思います。これにより、表示されているような問題が発生する可能性があります。

UIScreenからフレームを取得する代わりに、appDelegateの現在のキーウィンドウからフレームを取得することができます。

ただし、UIWindowが提供する機能が本当に必要なようには見えません。この目的のためにUIViewを使用するという他の人の推奨をエコーし​​たいと思います。 UIViewUIWindowよりも一般的であり、優先する必要があります。

1
Nick

最善の方法は、ウィンドウの代わりにビューを使用することです。

ほとんどのiOSアプリケーションは、存続期間中に1つのウィンドウのみを作成して使用します。このウィンドウはメイン画面全体に広がります[...]。ただし、アプリケーションがビデオ出力用の外部ディスプレイの使用をサポートしている場合は、その外部ディスプレイにコンテンツを表示するための追加のウィンドウを作成できます。他のすべてのウィンドウは通常、システムによって作成されます

ただし、複数のウィンドウを作成する正当な理由があると思われる場合は、サイズを自動的に処理するNSWindowのサブクラスを作成することをお勧めします。

また、特に3x Retina画面では、ウィンドウが大量のRAMを使用することにも注意してください。それらが複数あると、メモリ不足の警告を受け取って最終的に強制終了される前に、アプリケーションの残りの部分が使用できるメモリの量が減少します。

0
Abhi Beckert