ios 解除模态视图控制器时如何保持呈现视图控制器的方向?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24229677/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:54:59  来源:igfitidea点击:

How to maintain presenting view controller's orientation when dismissing modal view controller?

iosiphoneuiviewcontrollerswiftscreen-rotation

提问by Mihai Fratu

I have this app I am working on and I need ALL my view controllers but one to be in portrait. The single one view controller that is special I need it to be able to rotate to whatever orientation the phone is in.

我有我正在开发的这个应用程序,我需要我所有的视图控制器,但一个是纵向的。一个特殊的单一视图控制器,我需要它能够旋转到手机所处的任何方向。

To do that I present it modally (not embedded in a NavigationController)

为此,我以模态方式呈现它(未嵌入到 NavigationController 中)

So (for example) my structure is like this:

所以(例如)我的结构是这样的:

  • window - Portrait
    • root view controller (UINavigationController - Portrait)
      • home view controller (UIViewController - Portrait)
        • details view controller (UIViewController - Portrait)
        • .
        • .
        • .
        • modal view controller (UIVIewController - All)
  • 窗口 - 纵向
    • 根视图控制器(UINavigationController - Portrait)
      • 主视图控制器(UIViewController - 人像)
        • 详细信息视图控制器(UIViewController - Portrait)
        • .
        • .
        • .
        • 模态视图控制器(UIVIewController - 全部)

Now when ever I dismiss my modal view controller in a landscape position my parent view controller is ALSO rotated even though it doesn't support that orientation.

现在,当我在横向位置关闭我的模态视图控制器时,即使它不支持该方向,我的父视图控制器也会旋转。

All UIViewControllersand UINavigaionControllersin the app inherit from the same general classes which have these methods implemented:

所有UIViewControllersUINavigaionControllers在应用程序中都继承自已实现这些方法的相同通用类:

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

My modal view controller overrides this method once again and it looks like this:

我的模态视图控制器再次覆盖了这个方法,它看起来像这样:

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

Update 1

更新 1

It looks like this is happening only on iOS8 Beta. Does someone know if there is something that changed regarding view controller's rotation or is this just a bug in the beta?

看起来这种情况只发生在 iOS8 Beta 上。有人知道视图控制器的旋转是否发生了变化,或者这只是测试版中的错误?

采纳答案by ZaEeM ZaFaR

- (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;
}

And for 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());
    }

}

For more details check this link

有关更多详细信息,请查看此链接

回答by jules

I'm having the same issue with an app and after days of experimentation I came up with a solution which is not very nice but it works for now. I'm using the delegate method application:supportedInterfaceOrientationsForWindow:within the appdelegate.

我在应用程序上遇到了同样的问题,经过几天的实验,我想出了一个不太好的解决方案,但它现在有效。我application:supportedInterfaceOrientationsForWindow:在 appdelegate 中使用委托方法。

I created a test project and put it here on github(including a GIF which shows the result...)

我创建了一个测试项目并将其放在 github 上(包括显示结果的 GIF...)

// note: it's not in swift but I hope it helps anyways

// 注意:它不是很快,但我希望它无论如何都会有所帮助

回答by matt

After much experimentation, I am convinced that this is a "feature" of iOS 8.

经过多次试验,我确信这是 iOS 8 的一个“特性”。

If you think about it, this makes perfect sense, because it has been coming for a long time.

如果你仔细想想,这是完全有道理的,因为它已经出现了很长时间。

  • In, say iOS 4, it was possible to force app rotation when changing view controllers in a tab bar controller and a navigation controller, as well as when presenting/dismissing a controller.

  • Then in iOS 6 it became impossible to force app rotation except when presenting/dismissing a view controller (as I explained in many answers, such as this one).

  • Now, in iOS 8, I conjecture that it will be impossible to force app rotation at all (except at launch). It can prefera certain orientation, so that once it is in that orientation it will stay there, but it cannot forcethe app to go into that orientation.

    Instead, your view controller is expected to "adapt". There are several WWDC 2014 videos concentrating on "adaptation", and now I'm starting to understand that this is one reason why this is so important.

    EDIT:In seed 4, it looks like this feature (forcing rotation on presentation and dismissal) is returning!

  • 例如,在 iOS 4 中,可以在更改选项卡栏控制器和导航控制器中的视图控制器以及呈现/关闭控制器时强制应用程序旋转。

  • 然后在 iOS 6 中,除非呈现/关闭视图控制器,否则无法强制应用程序旋转(正如我在许多答案中所解释的,例如这个)。

  • 现在,在 iOS 8 中,我猜想根本不可能强制应用程序旋转(启动时除外)。它可以更喜欢某个方向,因此一旦它处于该方向,它就会留在那里,但它不能强制应用程序进入该方向。

    相反,您的视图控制器应该“适应”。有几个 WWDC 2014 视频专注于“适应”,现在我开始明白这是为什么这如此重要的原因之一。

    编辑:在种子 4 中,看起来这个功能(强制轮换演示和解雇)正在回归!

回答by Airsource Ltd

We have an app deployed that has a landscape controller which presents a portrait-only view controller. Was reviewed by Apple on iOS 8. We are only overriding supportedInterfaceOrientations.

我们部署了一个应用程序,该应用程序具有一个横向控制器,该控制器呈现一个仅限纵向的视图控制器。已在 iOS 8 上由 Apple 审核。我们仅覆盖了 supportedInterfaceOrientations。

It's worth noting that we found lots of differences between betas 3,4,and 5. In the end we had to wait for the GM before making a concerted effort to update our app for iOS 8.

值得注意的是,我们发现测试版 3、4 和 5 之间存在很多差异。最终我们不得不等待 GM 才齐心协力更新我们的 iOS 8 应用程序。

You need to be very careful in iOS 8 to make sure that you don't do this:

在 iOS 8 中你需要非常小心,以确保你不会这样做:

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

If the outgoing vc is portrait, and the incoming one is landscape, some view frames can end up very messed up. Present the incoming vc in the completion block of the dismiss call instead.

如果传出的 vc 是纵向的,而传入的 vc 是横向的,则某些视图帧可能会非常混乱。而是在解除调用的完成块中呈现传入的 vc。

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

回答by xfyre

This is actually easier and can be done without any additional properties (here's an example with AVPlayerViewController):

这实际上更容易,并且无需任何其他属性即可完成(这是一个带有 的示例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;
    }
}

回答by kuhr

Awesome question and awesome answer provided by @ZaEeM ZaFaR! Combining his answer with thisled me to a great and more generic solution.

@ZaEeM ZaFaR提供了很棒的问题和很棒的答案!将他的回答与这个结合起来,让我找到了一个更好、更通用的解决方案。

The drawback of the first answer is that you have to manage the variable isPresentedin every view controller that allows rotations. Furthermore, you have to expand the check and cast in supportedInterfaceOrientationsForWindowfor every vc that allows rotation.

第一个答案的缺点是您必须isPresented在每个允许旋转的视图控制器中管理变量。此外,您必须supportedInterfaceOrientationsForWindow为每个允许旋转的 vc扩展检查和强制转换。

The drawback of the second answer is that it doesn't work; it also rotates the presenting vc when dismissing the presented vc.

第二个答案的缺点是它不起作用;当关闭呈现的 vc 时,它还旋转呈现的 vc。

This solution allows rotation in all vc where you put canRotate(){} and doesn't rotate the presenting vc.

此解决方案允许在您放置 canRotate(){} 的所有 vc 中旋转,并且不旋转呈现的 vc。

Swift 3:
In AppDelegate.swift:

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
}

In each view controller where rotation should be allowed:

在每个允许旋转的视图控制器中:

func canRotate(){}

回答by Joshua C. Lerner

In the root view controller, try adding:

在根视图控制器中,尝试添加:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

Worked for me.

为我工作。

回答by Hiren Panchal

Swift 3.0 OR Above, Just check "isBeingDismissed" property of presented view controller. Below is sample code, This is will rotate presenting view controller to portrait mode immediately after presented view controller is dismissed.

Swift 3.0 或以上,只需检查呈现的视图控制器的“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}

you can get topController by below code:

您可以通过以下代码获取 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 }

回答by oren

I had the same issue, finally found a solution to open the modal view controller in another UIWindow, and it worked smoothly.

我遇到了同样的问题,终于找到了在另一个 UIWindow 中打开模态视图控制器的解决方案,并且运行顺利。

Stack - iOS8 - prevent rotation on presenting viewController

堆栈 - iOS8 - 防止旋转呈现 viewController

For code: https://github.com/OrenRosen/ModalInWindow

代码:https: //github.com/OrenRosen/ModalInWindow