web-dev-qa-db-ja.com

すべての上に表示:UIWindowサブビューVS UIViewControllerサブビュー

UIViewの動作のように、すべてのビューの上にUIAlertViewを作成するための最良の方法は、ビューをアプリウィンドウに追加することです。

[[[UIApplication sharedApplication] delegate] window]

しかし、私が見つけた欠点は、ローテーションが自動的に行われないことです。ローテーションを取得するための最善の方法は、現在のAppDelegate window.navigationController/rootViewControllerにビューを追加することです。ただし、これを行うと、すべての上に表示されなくなります。ビューが表示されているときにmodalViewControllerポップアップが表示された場合、モーダルビューがビューを確実に覆います。

私の質問は、最上位のウィンドウにサブビューを追加することは可能ですか?and support orientation?この場合、2セットのNibファイルが必要ですか? UIAlertViewは、最上部と方向のサポートを組み合わせるマジックをどのようにしていますか? UIAlertView.hを調べると、実際には2つのUIWindowsがあり、1つはoriginalWindowと呼ばれ、もう1つはdimWindowと呼ばれます。 UIAlertView.mのソースコードを見つけることができる場所はありますか?

27
Zian Chen

私が見つけた最良の解決策は、透明なコンテナビューを作成し、そのコンテナをウィンドウに追加し、アラートをコンテナ内に配置することです。その後、UIApplicationWillChangeStatusBarOrientationNotificationに登録して、回転イベントを受信し、コンテナーを変換できます。これにより、アラートのフレームを個別に操作できます。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
     ...
     self.container = [[UIView alloc] initWithFrame:self.window.bounds];
     [self.container addSubview:self.alertView];
     [self.window addSubview:self.container];
     [[NSNotificationCenter defaultCenter] addObserver:self 
                                              selector:@selector(statusBarWillRotate:) 
                                                  name:UIApplicationWillChangeStatusBarOrientationNotification 
                                                object:nil];
     ...
}
...
- (void)statusBarWillRotate:(NSNotification *)theNotification
{
    CGFloat rotation = 0;
    switch ([notification[UIApplicationStatusBarOrientationUserInfoKey] intValue])
    {
        case UIInterfaceOrientationLandscapeLeft:
            rotation = -M_PI_2;
            break;
        case UIInterfaceOrientationLandscapeRight:
            rotation = M_PI_2;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            rotation = M_PI;
            break;
        case UIInterfaceOrientationPortrait: 
        default:
            rotation = 0;
            break;
    }
    CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(rotation);
    CGSize rotatedSize = CGRectApplyAffineTransform(self.window.bounds, rotationTransform).size;
    [UIView animationWithDuration:[UIApplication sharedApplication].statusBarOrientationAnimationDuration
                       animations:^{
         self.container.transform = rotationTransform;
         // Transform invalidates the frame, so use bounds/center
         self.container.bounds = CGRectMake(0, 0, rotatedSize.width, rotatedSize.height);
         self.container.center = CGPointMake(self.window.bounds.size.width / 2, self.window.bounds.size.height / 2);
     }];
}

本当に必要な場合は、windowLevelプロパティをUIWindowLevelAlertに設定してまったく新しいウィンドウを作成できます。これにより、ウィンドウはキーボードを含む他のすべてのビューの上に残りますが、ウィンドウ管理かなりトリッキーになります。上記のソリューションは、ほとんどのニーズに十分なはずです。

View Controllerのビューをウィンドウに単純に追加する場合の問題は、すべての回転とview[Will|Did][Disa|A]ppear:メッセージ(View Controllerに追加されない場合)階層 via addChildViewController:ルートビューコントローラ。

15
Austin

UIWindowの最初のサブビューのみが方向の変更について通知されます。 (<iOS8)

あなたの質問はこれに非常に似ています:

IWindowの複数のビュー

そこの答えが示すように、方向の変更の通知に登録し、「トップ」サブビューの再レイアウトをそのように処理できます。

4
occulus

これが可能な解決策です。いくつかのステップで説明しています。

  1. UIViewControllerの代わりにUIView継承クラスで開始、TopViewControllerによって継承されたUIViewControllerという名前のクラスとしましょう
  2. UIViewの継承クラスにデバイス/インターフェースの回転を登録できないため、TopViewControllerから継承されたUIViewControllerクラスには、View Rotation Eventsに応答するメソッドがあります。ローテーションイベントをキャプチャできるようになりました。
  3. 最後に、質問で説明したのと同じ方法を使用して、TopViewControllerビューをUIWindowの上部に配置できます。

    [[[[UIApplication sharedApplication] delegate] window] addSubview:(TopViewController object).view];
    

お役に立てれば。

2
Rahul