在iOS 13中,模态视图控制器在呈现时有一个新的行为。

现在它不是全屏默认情况下,当我向下滑动时,应用会自动解除视图控制器。

我怎么能防止这种行为,并回到旧的全屏模态vc?

谢谢


当前回答

这对我很有效

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

其他回答

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

1-覆盖当前

如果你有一个BaseViewController,你可以重写present(_ viewcontrollertoppresent: 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)
  }

  // ....
}

使用这种方法,您不需要对任何present调用做任何更改,因为我们只是覆盖了present方法。

2-扩展:

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

用法:

presentInFullScreen(viewController, animated: true)

3-对于一个UIViewController

let viewController = UIViewController()
viewController.modalPresentationStyle = .fullScreen
present(viewController, animated: true, completion: nil)

4-从故事板

选择一个segue并将演示设置为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)
   }
}

用法: 在你的AppDelegate内部应用(_ application: didFinishLaunchingWithOptions)中添加这一行:

UIViewController.swizzlePresent()

使用这种方式,您不需要对任何present调用做任何更改,因为我们正在运行时替换present方法实现。 如果你想知道什么是swizzling,你可以查看这个链接: https://nshipster.com/swift-objc-runtime/

提示:如果你调用present to一个嵌入在NavigationController内部的ViewController,你必须将NavigationController设置为。fullscreen,而不是VC。

你可以像@davidbates这样做,也可以通过编程方式(像@pascalbros)这样做。

同样适用于UITabViewController

一个NavigationController的示例场景:

    //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)

我在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)
    }
}

然后放这个

UIViewController.preventPageSheetPresentation

的某个地方

例如在AppDelegate中

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

    UIViewController.preventPageSheetPresentation
    // ...
    return true
}

所有其他答案都足够了,但对于像我们这样的大型项目,导航是在代码和故事板中完成的,这是一项相当艰巨的任务。

对于那些积极使用Storyboard的人。这是我的建议:使用正则表达式。

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

<segue destination="Bof-iQ-svK" kind="presentation" identifier="importSystem" modalPresentationStyle="fullScreen" id="bfy-FP-mlc"/>

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

<segue destination="7DQ-Kj-yFD" kind="presentation" identifier="defaultLandingToSystemInfo" modalPresentationStyle="fullScreen" id="Mjn-t2-yxe"/>

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

搜索正则表达式

<segue destination="(.*)"\s* kind="show" identifier="(.*)" id="(.*)"/>

正则表达式替换

<segue destination="$1" kind="presentation" identifier="$2" modalPresentationStyle="fullScreen" id="$3"/>

为UIViewController创建一个类别(比如UIViewController+PresentationStyle)。向其添加以下代码。

 -(UIModalPresentationStyle)modalPresentationStyle{
     return UIModalPresentationStyleFullScreen;
}