全屏显示iOS 13中的模态

pas*_*ros 280 viewcontroller modalviewcontroller ios ios13

在iOS 13 Beta 1中,出现模态视图控制器时有新行为。现在默认情况下它不是全屏显示,当我尝试向下滑动时,该应用程序会自动关闭View Controller。

如何防止这种行为并回到旧的好全屏模式vc?

情态行为

谢谢

pas*_*ros 402

如WWDC 2019期间平台联盟中所述,使用iOS 13,Apple引入了新的默认卡演示文稿。为了强制全屏,您必须使用以下命令明确指定它:

let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen //or .overFullScreen for transparency
self.present(vc, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)

  • 我会说这不会在默认情况下持续很长时间。“ fullScreen”选项应为默认设置,以防止破坏UI更改。 (49认同)
  • 我不会指望这一点。过去,Apple经常更改默认设置,仅在与当前SDK链接后才激活默认设置。与以前的版本链接时,我们将“希望”获得旧的行为。 (8认同)
  • 我可以确认在iOS 13模拟器上运行的Xcode-10构建的应用程序仍默认为全屏显示。正如@DrMickeyLauer所说,使用Xcode 11进行构建会使该应用程序采用新的行为。使用`isModalInPresentation`阻止取消滑动手势。有关更多详细信息,请参见我的博客文章:https://medium.com/@hacknicity/view-controller-presentation-changes-in-ios-13-ac8c901ebc4e (6认同)
  • 时间已经过去,.automatic样式已确定为默认样式,(对于大多数视图控制器而言)为.pageSheet样式。但是,某些系统视图控制器可能会将其映射为其他样式。 (4认同)
  • 我建议使用.fullScreen而不是.overFullScreen。.fullScreen触发viewWillAppear和viewDidAppear,.overFullScreen则不执行 (3认同)

Ale*_*dro 116

我添加了对某人可能有用的信息。如果您有任何故事板segue,那么要回到旧样式,需要将kind属性设置为Present Modally并将Presentation属性设置为Full Screen

在此处输入图片说明

  • Interface Builder 中有没有办法设置 isModalInPresentation? (3认同)

dav*_*tes 67

在启动屏幕之后的初始视图中,我遇到了这个问题。因为没有定义顺序或逻辑,所以对我的解决方法是将演示文稿从自动切换到全屏,如下所示:

fix_storyboard_presentation_default_behavior

  • 有没有什么方法可以以编程方式对所有视图执行此操作,而不是通过故事板逐一执行此操作? (2认同)

Abe*_*eyh 52

有多种方法可以做到这一点,我认为每个项目都可以适合一个项目,但又不适合另一个项目,所以我认为我会保留在这里,也许其他人会遇到不同的情况。

1-覆盖存在

如果您有一个BaseViewController,则可以覆盖该present(_ viewControllerToPresent: animated flag: completion:)方法。

class BaseViewController: UIViewController {

  // ....

  override func present(_ viewControllerToPresent: UIViewController,
                        animated flag: Bool,
                        completion: (() -> Void)? = nil) {
    viewControllerToPresent.modalPresentationStyle = .fullScreen
    super.present(viewControllerToPresent, animated: flag, completion: completion)
  }

  // ....
}
Run Code Online (Sandbox Code Playgroud)

使用这种方式,您无需对任何present调用进行任何更改,因为我们只是覆盖了该present方法。

2-扩展名:

extension UIViewController {
  func presentInFullScreen(_ viewController: UIViewController,
                           animated: Bool,
                           completion: (() -> Void)? = nil) {
    viewController.modalPresentationStyle = .fullScreen
    present(viewController, animated: animated, completion: completion)
  }
}
Run Code Online (Sandbox Code Playgroud)

用法:

presentInFullScreen(viewController, animated: true)

Run Code Online (Sandbox Code Playgroud)

3-对于一个UIViewController

let viewController = UIViewController()
viewController.modalPresentationStyle = .fullScreen
present(viewController, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)

4-从情节提要

选择一个序列并将演示文稿设置为FullScreen
在此处输入图片说明

5-晃动

extension UIViewController {

  static func swizzlePresent() {

    let orginalSelector = #selector(present(_: animated: completion:))
    let swizzledSelector = #selector(swizzledPresent)

    guard let orginalMethod = class_getInstanceMethod(self, orginalSelector), let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) else{return}

    let didAddMethod = class_addMethod(self,
                                       orginalSelector,
                                       method_getImplementation(swizzledMethod),
                                       method_getTypeEncoding(swizzledMethod))

    if didAddMethod {
      class_replaceMethod(self,
                          swizzledSelector,
                          method_getImplementation(orginalMethod),
                          method_getTypeEncoding(orginalMethod))
    } else {
      method_exchangeImplementations(orginalMethod, swizzledMethod)
    }

  }

  @objc
  private func swizzledPresent(_ viewControllerToPresent: UIViewController,
                               animated flag: Bool,
                               completion: (() -> Void)? = nil) {
    if #available(iOS 13.0, *) {
      if viewControllerToPresent.modalPresentationStyle == .automatic {
        viewControllerToPresent.modalPresentationStyle = .fullScreen
      }
    }
    swizzledPresent(viewControllerToPresent, animated: flag, completion: completion)
   }
}
Run Code Online (Sandbox Code Playgroud)

用法:
在您的AppDelegate内部application(_ application: didFinishLaunchingWithOptions)添加以下行:

UIViewController.swizzlePresent()
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您不需要在任何当前调用上进行任何更改,因为我们正在运行时替换当前方法的实现。
如果您想知道什么在泛滥,可以查看以下链接:https : //nshipster.com/swift-objc-runtime/

  • Swizzling 是一个在一段时间内非常有效的解决方案。然而,当使用一些外部 SDK,例如 FacebookLogin(截至今天为 5.8)和 GoogleSignin 时,我注意到这种方法破坏了这些流程:我们在 iPad 上看到白屏。这可能是因为他们使用自己的 swizzling 方法 (4认同)

Pra*_*dha 43


一个班轮:

modalPresentationStyle需要在正在呈现导航控制器 上设置。


iOS 13 及以下 iOS 版本 fullScreenoverCurrentContextnavigationController

测试代码

let controller = UIViewController()
let navigationController = UINavigationController(rootViewController: controller)
navigationController.modalPresentationStyle = .overCurrentContext
self.navigationController?.present(navigationController, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)

modalPresentationStyle需要在navigationController 中设置。


ved*_*ano 28

我需要同时做:

  1. 将演示样式设置为全屏

    全屏

  2. 将顶部栏设置为半透明导航栏

顶栏


9to*_*ios 25

对于Objective-C用户

只需使用此代码

 [vc setModalPresentationStyle: UIModalPresentationFullScreen];
Run Code Online (Sandbox Code Playgroud)

或者,如果要在iOS 13.0中添加它,请使用

 if (@available(iOS 13.0, *)) {
     [vc setModalPresentationStyle: UIModalPresentationFullScreen];
 } else {
     // Fallback on earlier versions
 }
Run Code Online (Sandbox Code Playgroud)

  • UIModalPresentationFullScreen可与iOS 3.2及更高版本一起使用。因此,如果没有其他条件,则无需添加。 (3认同)
  • 这也适用于早期的ios版本,但是答案很好 (2认同)
  • 由于某些原因,仅在iOS 13.1.2中,仅在Obj-c类中,此方法不起作用,而modalPresentationStyle仅显示pageSheet。这会发生在其他人身上吗? (2认同)

mum*_*umu 25

适用于 iOS 13 和 Swift 5.x 的最新版本

let vc = ViewController(nibName: "ViewController", bundle: nil)
Run Code Online (Sandbox Code Playgroud)

vc.modalPresentationStyle = .fullScreen

self.present(vc, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)


kuz*_*zdu 20

提示:如果您对存在于ViewController内嵌的的调用present ,则NavigationController必须将设置为NavigationController.fullScreen而不是VC。

您可以像@davidbates一样执行此操作,也可以通过编程方式(例如@pascalbros)来执行。

一个示例场景:

在此处输入图片说明

    //BaseNavigationController: UINavigationController {}
    let baseNavigationController = storyboard!.instantiateViewController(withIdentifier: "BaseNavigationController")
    var navigationController = UINavigationController(rootViewController: baseNavigationController)
    navigationController.modalPresentationStyle = .fullScreen
    navigationController.topViewController as? LoginViewController
    self.present(navigationViewController, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)


Gur*_*i S 20

这对我有用

let vc = self.storyboard?.instantiateViewController(withIdentifier: "storyboardID_cameraview1") as! CameraViewController
  
vc.modalPresentationStyle = .fullScreen
    
self.present(vc, animated: true, completion: nil)`
Run Code Online (Sandbox Code Playgroud)


Ran*_*jaz 18

快速解决。上面已经有很好的答案。我还添加了我的快速 2 点输入,它显示在屏幕截图中。

  1. 如果您不使用Navigation ControllerRight Menu Inspector则将 Presentation 设置为Full Screen

  2. 如果您正在使用,Navigation Controller则默认情况下它将全屏显示,您无需执行任何操作。

在此处输入图片说明


Max*_*rov 16

我在iOS 13上使用了swizzling

import Foundation
import UIKit

private func _swizzling(forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
    if let originalMethod = class_getInstanceMethod(forClass, originalSelector),
       let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector) {
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}

extension UIViewController {

    static let preventPageSheetPresentation: Void = {
        if #available(iOS 13, *) {
            _swizzling(forClass: UIViewController.self,
                       originalSelector: #selector(present(_: animated: completion:)),
                       swizzledSelector: #selector(_swizzledPresent(_: animated: completion:)))
        }
    }()

    @available(iOS 13.0, *)
    @objc private func _swizzledPresent(_ viewControllerToPresent: UIViewController,
                                        animated flag: Bool,
                                        completion: (() -> Void)? = nil) {
        if viewControllerToPresent.modalPresentationStyle == .pageSheet
                   || viewControllerToPresent.modalPresentationStyle == .automatic {
            viewControllerToPresent.modalPresentationStyle = .fullScreen
        }
        _swizzledPresent(viewControllerToPresent, animated: flag, completion: completion)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后把这个

UIViewController.preventPageSheetPresentation
Run Code Online (Sandbox Code Playgroud)

某处

例如在AppDelegate中

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {

    UIViewController.preventPageSheetPresentation
    // ...
    return true
}
Run Code Online (Sandbox Code Playgroud)


Di *_*erd 10

如果您的UITabController具有带嵌入式导航控制器的屏幕,则必须将UITabController Presentation设置为FullScreen,如下图所示

在此处输入图片说明


Mah*_*iya 9

这是一个简单的解决方案,无需编码一行。

  • 在情节提要中选择视图控制器
  • 选择属性检查器
  • 如下图所示,将演示文稿“自动”设置为“全屏”

此更改使iPad应用程序的行为符合预期,否则新屏幕将在弹出窗口的中央显示。

在此处输入图片说明


Ale*_*hov 9

这是我在 ObjectiveC 中使用类别进行修复的版本。使用这种方法,您将拥有默认的 UIModalPresentationStyleFullScreen 行为,直到另一个明确设置。

#import "UIViewController+Presentation.h"
#import "objc/runtime.h"

@implementation UIViewController (Presentation)

- (void)setModalPresentationStyle:(UIModalPresentationStyle)modalPresentationStyle {
    [self setPrivateModalPresentationStyle:modalPresentationStyle];
}

-(UIModalPresentationStyle)modalPresentationStyle {
    UIModalPresentationStyle style = [self privateModalPresentationStyle];
    if (style == NSNotFound) {
        return UIModalPresentationFullScreen;
    }
    return style;
}

- (void)setPrivateModalPresentationStyle:(UIModalPresentationStyle)modalPresentationStyle {
    NSNumber *styleNumber = [NSNumber numberWithInteger:modalPresentationStyle];
     objc_setAssociatedObject(self, @selector(privateModalPresentationStyle), styleNumber, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIModalPresentationStyle)privateModalPresentationStyle {
    NSNumber *styleNumber = objc_getAssociatedObject(self, @selector(privateModalPresentationStyle));
    if (styleNumber == nil) {
        return NSNotFound;
    }
    return styleNumber.integerValue;
}

@end
Run Code Online (Sandbox Code Playgroud)


sko*_*nos 9

设置navigationController.modalPresentationStyle.fullScreen已经在这里重复了一千多次,但让我向您展示另一个阻止程序,它导致即使所有属性都设置正确,UIViewController/UINavigationController也没有显示。fullscreen

就我而言,罪魁祸首隐藏在这一行中

navigationController?.presentationController?.delegate = self
Run Code Online (Sandbox Code Playgroud)

显然,在设置时,UIAdaptivePresentationControllerDelegate您需要在可选委托方法中指定呈现样式

    public func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        presentationStyle
    }
Run Code Online (Sandbox Code Playgroud)


Ban*_*ali 6

所有其他答案都足够了,但是对于像我们这样的大型项目来说,无论是在代码还是在情节提要中进行导航,这都是一项艰巨的任务。

在此处输入图片说明

对于那些正在积极使用Storyboard的人。这是我的建议:使用Regex。

以下格式不适用于全屏页面:

<segue destination="Bof-iQ-svK" kind="presentation" identifier="importSystem" modalPresentationStyle="fullScreen" id="bfy-FP-mlc"/>
Run Code Online (Sandbox Code Playgroud)

以下格式适合全屏页面:

<segue destination="7DQ-Kj-yFD" kind="presentation" identifier="defaultLandingToSystemInfo" modalPresentationStyle="fullScreen" id="Mjn-t2-yxe"/>
Run Code Online (Sandbox Code Playgroud)

以下与VS CODE兼容的正则表达式会将所有旧样式页面转换为新样式页面。如果您使用其他正则表达式引擎/文本编辑器,则可能需要转义特殊字符。

搜索正则表达式

<segue destination="(.*)"\s* kind="show" identifier="(.*)" id="(.*)"/>
Run Code Online (Sandbox Code Playgroud)

替换正则表达式

<segue destination="$1" kind="presentation" identifier="$2" modalPresentationStyle="fullScreen" id="$3"/>
Run Code Online (Sandbox Code Playgroud)


Yog*_*ate 5

最初,默认值是fullscreenmodalPresentationStyle,但在iOS 13 中它更改为UIModalPresentationStyle.automatic.

如果要制作全屏视图控制器,则必须modalPresentationStylefullScreen.

有关更多详细信息,请参阅UIModalPresentationStyle 苹果文档,并参阅苹果人机界面指南以了解应在何处使用哪种模式。


小智 5

这是Objective-C的解决方案

UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:@"ViewController"];

vc.modalPresentationStyle = UIModalPresentationFullScreen;

[self presentViewController:vc animated:YES completion:nil];
Run Code Online (Sandbox Code Playgroud)


Mal*_*n C 5

正如 WWDC 2019 期间的平台联盟声明所述,Apple 在 iOS 13 中引入了新的默认卡片呈现方式。为了强制全屏,你必须明确指定它:

let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen //or .overFullScreen for transparency
self.navigationViewController.present(vc, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)