How to change the background color of the UIAlertController?

38,247

Solution 1

You have to step some views deeper:

let subview = actionController.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
alertContentView.backgroundColor = UIColor.blackColor()

And maybe you want to keep original corner radius:

 alertContentView.layer.cornerRadius = 5;

Sorry for the "Swifting" but i'm not familiar with Objective-C. I hope that's similar.

Of course it's also important to change the title color of the actions. Unfortunately I don't know, how to set the color of actions separately. But this is, how you change all button text colors:

actionController.view.tintColor = UIColor.whiteColor();

EDIT:

The corner radius of the UIAlertController has changed since this answer's been posted! Replace this:

 alertContentView.layer.cornerRadius = 5;

to this:

 actionContentView.layer.cornerRadius = 15

Solution 2

maybe you like the use the blur effect in the dark mode. Here is a very easy way to get this:

UIVisualEffectView.appearance(whenContainedInInstancesOf: [UIAlertController.classForCoder() as! UIAppearanceContainer.Type]).effect = UIBlurEffect(style: .dark)

Solution 3

I have found a hack-ish way of doing it. First you need an extension to allow you to search for the UIVisualEffectView inside the UIAlertController:

extension UIView
{
    func searchVisualEffectsSubview() -> UIVisualEffectView?
    {
        if let visualEffectView = self as? UIVisualEffectView
        {
            return visualEffectView
        }
        else
        {
            for subview in subviews
            {
                if let found = subview.searchVisualEffectsSubview()
                {
                    return found
                }
            }
        }

        return nil
    }
}

Important: You have to call this function after calling presentViewController, because only after loading the view controller that the visual effects view is inserted into place. Then you can change the effect associated with it to a dark blur effect:

self.presentViewController(actionController, animated: true, completion: nil)

if let visualEffectView = actionController.view.searchVisualEffectsSubview()
{
    visualEffectView.effect = UIBlurEffect(style: .Dark)
}

And this is the final result:

demo picture

I am honestly surprised myself how well it works! I think this is probably something Apple forgot to add. Also, I haven't yet passed an App through approval with this "hack" (it isn't a hack because we're only using public APIs), but I'm confident there won't be a problem.

Solution 4

for Swift 3/ Swift 4

let subview =(alert.view.subviews.first?.subviews.first?.subviews.first!)! as UIView

            subview.backgroundColor = UIColor(red: (145/255.0), green: (200/255.0), blue: (0/255.0), alpha: 1.0)

            alert.view.tintColor = UIColor.black

enter image description here.

Solution 5

Here is a UIAlertController extension that works on both iPad and iPhone. Cancel button will change from a dark colour to white automatically depending on what blurStyle is selected:

extension UIAlertController {

    private struct AssociatedKeys {
        static var blurStyleKey = "UIAlertController.blurStyleKey"
    }

    public var blurStyle: UIBlurEffectStyle {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.blurStyleKey) as? UIBlurEffectStyle ?? .extraLight
        } set (style) {
            objc_setAssociatedObject(self, &AssociatedKeys.blurStyleKey, style, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

            view.setNeedsLayout()
            view.layoutIfNeeded()
        }
    }

    public var cancelButtonColor: UIColor? {
        return blurStyle == .dark ? UIColor(red: 28.0/255.0, green: 28.0/255.0, blue: 28.0/255.0, alpha: 1.0) : nil
    }

    private var visualEffectView: UIVisualEffectView? {
        if let presentationController = presentationController, presentationController.responds(to: Selector(("popoverView"))), let view = presentationController.value(forKey: "popoverView") as? UIView // We're on an iPad and visual effect view is in a different place.
        {
            return view.recursiveSubviews.flatMap({$0 as? UIVisualEffectView}).first
        }

        return view.recursiveSubviews.flatMap({$0 as? UIVisualEffectView}).first
    }

    private var cancelActionView: UIView? {
        return view.recursiveSubviews.flatMap({
            $0 as? UILabel}
        ).first(where: {
            $0.text == actions.first(where: { $0.style == .cancel })?.title
        })?.superview?.superview
    }

    public convenience init(title: String?, message: String?, preferredStyle: UIAlertControllerStyle, blurStyle: UIBlurEffectStyle) {
        self.init(title: title, message: message, preferredStyle: preferredStyle)
        self.blurStyle = blurStyle
    }

    open override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        visualEffectView?.effect = UIBlurEffect(style: blurStyle)
        cancelActionView?.backgroundColor = cancelButtonColor
    }
}

The following UIView extension is also needed:

extension UIView {

    var recursiveSubviews: [UIView] {
        var subviews = self.subviews.flatMap({$0})
        subviews.forEach { subviews.append(contentsOf: $0.recursiveSubviews) }
        return subviews
    }
}

Example:

let controller = UIAlertController(title: "Dark Alert Controller", message: nil, preferredStyle: .actionSheet, blurStyle: .dark)

// Setup controller actions etc...

present(controller, animated: true, completion: nil)

iPhone:

enter image description here

iPad:

enter image description here

Share:
38,247
GJDK
Author by

GJDK

Updated on February 25, 2020

Comments

  • GJDK
    GJDK over 4 years

    Due to strange behavior of UIActionSheet in iOS 8, I have implemented UIAlertController with UIAction as buttons in it. I would like to change the entire background of the UIAlertController. But I can't find any ways to do it.

    Tried even with,

    actionController.view.backgroundColor = [UIColor blackColor];
    

    But didn't help me out. Any inputs on this regard will be appreciable.

    Thanks in advance.