How to change the background color of the UIAlertController?
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:
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
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:
iPad:
GJDK
Updated on February 25, 2020Comments
-
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.