Presenting modal in iOS 13 fullscreen

后端 未结 30 2096
囚心锁ツ
囚心锁ツ 2020-11-21 06:48

In iOS 13 there is a new behaviour for modal view controller when being presented.

Now it\'s not fullscreen by default and when I try to slide down, the app just dis

30条回答
  •  孤独总比滥情好
    2020-11-21 07:02

    There are multiple ways to do that, and I think each one could fit for one project but not another, so I thought I'll keep them here maybe someone else will run to a different case.

    1- Override present

    If you have a BaseViewController you can override the present(_ viewControllerToPresent: animated flag: completion:) method.

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

    Using this way you don't need to do any change on any present call, as we just overrode the present method.

    2- An extension:

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

    Usage:

    presentInFullScreen(viewController, animated: true)
    
    

    3- For one UIViewController

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

    4- From Storyboard

    Select a segue and set the presentation to FullScreen.

    5- Swizzling

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

    Usage:
    In your AppDelegate inside application(_ application: didFinishLaunchingWithOptions) add this line:

    UIViewController.swizzlePresent()
    

    Using this way you don't need to do any change on any present call, as we are replacing the present method implementation in runtime.
    If you need to know what is swizzling you can check this link: https://nshipster.com/swift-objc-runtime/

提交回复
热议问题