web-dev-qa-db-ja.com

モーダルView Controllerを閉じるときに、View Controllerの表示方向を維持するにはどうすればよいですか?

作業中のこのアプリがあり、ビューコントローラーを1つだけ使用する必要があります。特別な単一の1つのView Controllerは、携帯電話がどんな方向にでも回転できるようにするために必要です。

そのために、モーダルモードで表示します(NavigationControllerに埋め込まれません)

(たとえば)私の構造は次のようになります:

  • ウィンドウ-ポートレート
    • ルートビューコントローラー(UINavigationController-Portrait)
      • ホームビューコントローラー(UIViewController-Portrait)
        • 詳細ビューコントローラー(UIViewController-Portrait)
        • モーダルビューコントローラー(UIVIewController-すべて)

横向きでモーダルビューコントローラーを閉じると、親のビューコントローラーはその方向をサポートしていなくても回転します。

アプリ内のすべてのUIViewControllersおよびUINavigaionControllersは、これらのメソッドが実装されている同じ一般クラスから継承します。

override func supportedInterfaceOrientations() -> Int
{
    return Int(UIInterfaceOrientationMask.Portrait.toRaw())
}

私のモーダルView Controllerはこのメソッドをもう一度オーバーライドし、次のようになります。

override func supportedInterfaceOrientations() -> Int
{
    return Int(UIInterfaceOrientationMask.All.toRaw())
}

更新1

これはiOS8 Betaでのみ発生しているようです。 View Controllerの回転に関して変更されたものがあるのか​​、これはベータ版の単なるバグなのかを誰かが知っていますか?

32
Mihai Fratu
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
    SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;

    if (secondController.isPresented)
        return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}

Swiftの場合

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {

    if self.window?.rootViewController?.presentedViewController? is SecondViewController {

        let secondController = self.window!.rootViewController.presentedViewController as SecondViewController

        if secondController.isPresented {
            return Int(UIInterfaceOrientationMask.All.toRaw());
        } else {
            return Int(UIInterfaceOrientationMask.Portrait.toRaw());
        }
    } else {
        return Int(UIInterfaceOrientationMask.Portrait.toRaw());
    }

}

詳細については、これを確認してください link

18
ZaEeM ZaFaR

私はアプリで同じ問題を抱えており、数日間の実験の後、あまりいいとは言えない解決策を思い付きましたが、今のところはうまくいきます。 appdelegate内でデリゲートメソッドapplication:supportedInterfaceOrientationsForWindow:を使用しています。

テストプロジェクトを作成し、それを配置します ここではgithub (結果を表示するGIFを含む...)

//注:Swiftではありませんが、とにかく役立つことを願っています

7
jules

多くの実験を重ねた結果、これはiOS 8の「機能」であると確信しています。

あなたがそれについて考えるならば、これは長い間来ているので、これは完全に理にかなっています。

  • たとえば、iOS 4では、Tab Bar ControllerおよびNavigation ControllerのView Controllerを変更するとき、およびコントローラーを表示/非表示にするときに、アプリの回転を強制することができました。

  • その後、iOS 6では、View Controllerを表示/非表示にする場合を除き、アプリの回転を強制することができなくなりました( this one など、多くの回答で説明したように)。

  • さて、iOS 8では、アプリのローテーションを強制することはまったく不可能だと推測しています(起動時を除く)。特定の向きを優先することができるため、その向きになるとそこにとどまりますが、アプリを強制することはできませんそのオリエンテーションに入ります。

    代わりに、View Controllerは「適応する」ことが期待されています。 「適応」に焦点を当てたWWDC 2014ビデオがいくつかありますが、これがこれが非常に重要な理由の1つであることが理解され始めています。

    EDIT:シード4では、この機能(プレゼンテーションと解雇の強制回転)が戻ってきているようです!

4
matt

ポートレートのみのView Controllerを表示するLandscape Controllerを備えたアプリをデプロイしました。 iOS 8のAppleによってレビューされました。supportedInterfaceOrientationsのみをオーバーライドしています。

ベータ3,4、および5の間に多くの違いを見つけたことは注目に値します。最終的に、iOS 8用のアプリを更新するために協力して努力する前に、GMを待たなければなりませんでした。

IOS 8では、これを行わないように非常に注意する必要があります。

[self dismissViewControllerAnimated:YES completion:nil]
[self presentViewController:vc animated:YES completion:nil]

発信vcがポートレートで、着信vcがランドスケープである場合、一部のビューフレームが非常に混乱する可能性があります。代わりに、着信呼び出しの終了ブロックで着信vcを提示します。

[self dismissViewControllerAnimated:YES completion:^{
    [self presentViewController:vc animated:YES completion:nil]
}];
3
Airsource Ltd

これは実際には簡単で、追加のプロパティなしで実行できます(AVPlayerViewControllerの例です):

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        if ([self.window.rootViewController.presentedViewController isKindOfClass: [AVPlayerViewController class]])
            return self.window.rootViewController.presentedViewController.isBeingDismissed ? 
            UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskAll;
        else
            return UIInterfaceOrientationMaskPortrait;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}
2
xfyre

@ ZaEeM ZaFaR !が提供する素晴らしい質問と素晴らしい回答彼の答えと this を組み合わせることで、より優れた、より一般的なソリューションになりました。

最初の答えの欠点は、回転を許可するすべてのView Controllerで変数isPresentedを管理する必要があることです。さらに、チェックを展開し、回転を許可するすべてのvcに対してsupportedInterfaceOrientationsForWindowをキャストする必要があります。

2番目の答えの欠点は、機能しないことです。また、提示されたvcを閉じるときに、提示されたvcを回転させます。

このソリューションは、canRotate(){}を配置するすべてのvcで回転を許可し、提示するvcを回転させません。

Swift 3:
AppDelegate.Swiftの場合:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
        if (rootViewController.responds(to: Selector(("canRotate")))) {
            // Unlock landscape view orientations for this view controller if it is not currently being dismissed
            if !rootViewController.isBeingDismissed{
                return .allButUpsideDown
            }
        }
    }

    // Only allow portrait (standard behaviour)
    return .portrait
}

private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
    if (rootViewController == nil) {
        return nil
    }
    if (rootViewController.isKind(of: UITabBarController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
    } else if (rootViewController.isKind(of: UINavigationController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
    } else if (rootViewController.presentedViewController != nil) {
        return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
    }
    return rootViewController
}

回転を許可する各View Controllerで:

func canRotate(){}
1
kuhr

ルートView Controllerで、以下を追加してみてください:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

私のために働いた。

1

Swift 3.0 OR上記、表示されたView Controllerの「isBeingDismissed」プロパティを確認するだけです。以下はサンプルコードです。

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController)
{
  if rootViewController.canRotateVC == true
  {
    if baseVC.isBeingDismissed == false
    {
      return .allButUpsideDown
    }
  }
}

  return .portrait}

以下のコードでtopControllerを取得できます。

  private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController?{
if (rootViewController == nil) { return nil }if (rootViewController.isKind(of: (UITabBarController).self))
{
  return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
}
else if (rootViewController.isKind(of:(UINavigationController).self))
{
  return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
}
else if (rootViewController.presentedViewController != nil)
{
  return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController }
0
Hiren Panchal