3

When I present a UIAlertController over a view controller, the controls are dimmed as expected.

However, if the same view controller is itself modally presented, the display of the alert controller does not dim the controls (the two buttons remain blue).

How do I make a presented view controller itself handle presentations correctly, and dim its controls?

Here is a small example project. The relevant code is in MainViewController.swift.

Ben Packard
  • 26,102
  • 25
  • 102
  • 183
  • I don’t know why they don’t dim, but is easy to dim them yourself if you have to. https://developer.apple.com/documentation/uikit/uiview/tintadjustmentmode/dimmed – matt Jun 02 '19 at 20:12
  • Thanks, my question is why they *don't* dim automatically and how to have them do so - I'm aware of the workarounds. I don't think it is scalable for me to manually set the `tintAdjustmentMode` to `dimmed` every time I present anything that isn't full screen, and then back again afterwards. I could understand it with some custom controls, or perhaps some nested view controllers. But this is a trivial example that should 'just work', right? I am looking for a more thorough understanding of this API, not just a quick fix. – Ben Packard Jun 02 '19 at 21:02
  • Should also note that it is not straightforward to dim ones own views when the alert originates from the OS, for example when a camera permission alert is displayed. – Ben Packard Dec 03 '19 at 12:55

1 Answers1

0

The best workaround I have so far is to use a customized UIAlertController subclass to set the tintAdjustmentMode alongside its appear/disappear animations, using the transitionCoordinator:

/// A `UIAlertController` that can udpates its presenting view controller's `tintAdjustmentMode` code as it appears and disappears
class TintAdjustingAlertController: UIAlertController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        animatePresentingViewTintAdjustmentMode(tintAdjustmentMode: .dimmed, forViewControllerAtKey: .from)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        animatePresentingViewTintAdjustmentMode(tintAdjustmentMode: .automatic, forViewControllerAtKey: .to)
    }

    private func animatePresentingViewTintAdjustmentMode(tintAdjustmentMode mode: UIView.TintAdjustmentMode, forViewControllerAtKey key: UITransitionContextViewControllerKey) {
        transitionCoordinator?.animate(alongsideTransition: { context in
            if let presentingNavigationController = context.viewController(forKey: key) as? UINavigationController {
                presentingNavigationController.navigationBar.tintAdjustmentMode = mode
                presentingNavigationController.viewControllers.forEach { $0.view.tintAdjustmentMode = mode }
            } else if let presentingViewController = context.viewController(forKey: key) {
                presentingViewController.view.tintAdjustmentMode = mode
            }
            }, completion: nil)
    }
}

This works, but I hope not to have to pepper it throughout my code. Would still love to know a) if there is a simple way to make this work as expected, or b) if this is indeed an iOS bug, is there a more elegant workaround?

I have also submitted a radar for this: http://www.openradar.me/radar?id=6113750608248832

Ben Packard
  • 26,102
  • 25
  • 102
  • 183