How to present UIAlertController when not in a view controller?

前端 未结 30 3506
庸人自扰
庸人自扰 2020-11-22 06:21

Scenario: The user taps on a button on a view controller. The view controller is the topmost (obviously) in the navigation stack. The tap invokes a utility class method call

30条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-11-22 07:16

    Swift 4+

    Solution I use for years with no issues at all. First of all I extend UIWindow to find it's visibleViewController. NOTE: if you using custom collection* classes (such as side menu) you should add handler for this case in following extension. After getting top most view controller it's easy to present UIAlertController just like UIAlertView.

    extension UIAlertController {
    
      func show(animated: Bool = true, completion: (() -> Void)? = nil) {
        if let visibleViewController = UIApplication.shared.keyWindow?.visibleViewController {
          visibleViewController.present(self, animated: animated, completion: completion)
        }
      }
    
    }
    
    extension UIWindow {
    
      var visibleViewController: UIViewController? {
        guard let rootViewController = rootViewController else {
          return nil
        }
        return visibleViewController(for: rootViewController)
      }
    
      private func visibleViewController(for controller: UIViewController) -> UIViewController {
        var nextOnStackViewController: UIViewController? = nil
        if let presented = controller.presentedViewController {
          nextOnStackViewController = presented
        } else if let navigationController = controller as? UINavigationController,
          let visible = navigationController.visibleViewController {
          nextOnStackViewController = visible
        } else if let tabBarController = controller as? UITabBarController,
          let visible = (tabBarController.selectedViewController ??
            tabBarController.presentedViewController) {
          nextOnStackViewController = visible
        }
    
        if let nextOnStackViewController = nextOnStackViewController {
          return visibleViewController(for: nextOnStackViewController)
        } else {
          return controller
        }
      }
    
    }
    

提交回复
热议问题