简体   繁体   English

如何更改UIAlertController的背景颜色?

[英]How to change the background color of the UIAlertController?

Due to strange behavior of UIActionSheet in iOS 8, I have implemented UIAlertController with UIAction as buttons in it. 由于UIActionSheet在iOS 8中的奇怪行为,我已经将UIAlertController与UIAction一起实现为按钮。 I would like to change the entire background of the UIAlertController. 我想改变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. 提前致谢。

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. 对不起“Swifting”,但我不熟悉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! 自这个答案发布以来, UIAlertController的角半径已经改变了! Replace this: 替换这个:

 alertContentView.layer.cornerRadius = 5;

to this: 对此:

 actionContentView.layer.cornerRadius = 15

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)

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 : 首先,您需要一个扩展来允许您在UIVisualEffectView搜索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. 重要提示 :调用presentViewController 必须调用此函数,因为只有在加载视图控制器后才能将视觉效果视图插入到位。 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. 我想这可能是Apple忘记添加的内容。 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. 此外,我还没有通过与批准通过了一个应用这种“黑客”(这是不是黑客攻击,因为我们只使用公共API),但我相信不会有问题。

for Swift 3/ Swift 4 对于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

在此输入图像描述 .

Here is a UIAlertController extension that works on both iPad and iPhone. 这是一个适用于iPad和iPhone的UIAlertController扩展。 Cancel button will change from a dark colour to white automatically depending on what blurStyle is selected: 取决于所选的blurStyle,取消按钮将自动从深色变为白色:

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: 还需要以下UIView扩展:

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: iPad的:

在此输入图像描述

Swift3 Swift3

Step into one more layer compare with swift2 再加上一层与swift2比较

    let subview1 = alert.view.subviews.first! as UIView
    let subview2 = subview1.subviews.first! as UIView
    let view = subview2.subviews.first! as UIView

    subview.backgroundColor = backgroundColor
    view.backgroundColor = backgroundColor
    view.layer.cornerRadius = 10.0

    // set color to UILabel font
    setSubviewLabelsToTextColor(textColor, view: view)

    // set font to alert via KVC, otherwise it'll get overwritten
    let titleAttributed = NSMutableAttributedString(
        string: alert.title!,
        attributes: [NSFontAttributeName:UIFont.boldSystemFont(ofSize: 17)])
    alert.setValue(titleAttributed, forKey: "attributedTitle")

    let messageAttributed = NSMutableAttributedString(
        string: alert.message!,
        attributes: [NSFontAttributeName:UIFont.systemFont(ofSize: 13)])
    alert.setValue(messageAttributed, forKey: "attributedMessage")

    // set the buttons to non-blue, if we have buttons
    if let buttonColor = buttonColor {
        alert.view.tintColor = buttonColor
    }
func Alert(View: ViewController, Title: String, TitleColor: UIColor, Message: String, MessageColor: UIColor, BackgroundColor: UIColor, BorderColor: UIColor, ButtonColor: UIColor) {

    let TitleString = NSAttributedString(string: Title, attributes: [NSFontAttributeName : UIFont.systemFontOfSize(15), NSForegroundColorAttributeName : TitleColor])
    let MessageString = NSAttributedString(string: Message, attributes: [NSFontAttributeName : UIFont.systemFontOfSize(15), NSForegroundColorAttributeName : MessageColor])

    let alertController = UIAlertController(title: Title, message: Message, preferredStyle: .Alert)

    alertController.setValue(TitleString, forKey: "attributedTitle")
    alertController.setValue(MessageString, forKey: "attributedMessage")

    let okAction = UIAlertAction(title: "OK", style: .Default) { (action) in

    }

    let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: nil)

    alertController.addAction(okAction)
    alertController.addAction(cancelAction)


    let subview = alertController.view.subviews.first! as UIView
    let alertContentView = subview.subviews.first! as UIView
    alertContentView.backgroundColor = BackgroundColor
    alertContentView.layer.cornerRadius = 10
    alertContentView.alpha = 1
    alertContentView.layer.borderWidth = 1
    alertContentView.layer.borderColor = BorderColor.CGColor


    //alertContentView.tintColor = UIColor.whiteColor()
    alertController.view.tintColor = ButtonColor

    View.presentViewController(alertController, animated: true) {
        // ...
    }
}

For Objective - C Code May be Like. 对于Objective - C Code可能是喜欢的。

UIAlertController * alert=[UIAlertController alertControllerWithTitle:@"Title"
                                                              message:@"Message"
                                                       preferredStyle:UIAlertControllerStyleAlert];
UIView *firstSubview = alert.view.subviews.firstObject;
UIView *alertContentView = firstSubview.subviews.firstObject;
for (UIView *subSubView in alertContentView.subviews) {
    subSubView.backgroundColor = [UIColor colorWithRed:255/255.0f green:255/255.0f blue:255/255.0f alpha:1.0f];
}
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){
   //Close Action
}];
[alert addAction:cancelAction];
[self presentViewController:alert animated:YES completion:nil];

The best decision that i found (without white spots on the sides) 我找到的最佳决定(两侧没有白点)

Link to original answer by Vadim Akhmerov 链接到 Vadim Akhmerov的 原始答案

Answer: 回答:

It is easier to subclass UIAlertController . UIAlertController子类UIAlertController更容易。

The idea is to traverse through view hierarchy each time viewDidLayoutSubviews gets called, remove effect for UIVisualEffectView 's and update their backgroundColor : 我的想法是每次调用viewDidLayoutSubviews时遍历视图层次结构,删除UIVisualEffectView的效果并更新其backgroundColor

class AlertController: UIAlertController {

    /// Buttons background color.
    var buttonBackgroundColor: UIColor = .darkGray {
        didSet {
            // Invalidate current colors on change.
            view.setNeedsLayout()
        }
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // Traverse view hierarchy.
        view.allViews.forEach {
            // If there was any non-clear background color, update to custom background.
            if let color = $0.backgroundColor, color != .clear {
                $0.backgroundColor = buttonBackgroundColor
            }
            // If view is UIVisualEffectView, remove it's effect and customise color.
            if let visualEffectView = $0 as? UIVisualEffectView {
                visualEffectView.effect = nil
                visualEffectView.backgroundColor = buttonBackgroundColor
            }
        }

        // Update background color of popoverPresentationController (for iPads).
        popoverPresentationController?.backgroundColor = buttonBackgroundColor
    }

}


extension UIView {

    /// All child subviews in view hierarchy plus self.
    fileprivate var allViews: [UIView] {
        var views = [self]
        subviews.forEach {
            views.append(contentsOf: $0.allViews)
        }

        return views
    }

}

Usage: 用法:

  1. Create alert controller(use now AlertController instead UIAlertController) 创建警报控制器(现在使用AlertController而不是UIAlertController)

let testAlertController = AlertController(title: nil, message: nil, preferredStyle: .actionSheet) 让testAlertController = AlertController(title:nil,message:nil,preferredStyle:.actionSheet)

  1. Set background color on custom class "AlertController": 在自定义类“AlertController”上设置背景颜色:

var buttonBackgroundColor: UIColor = .darkGray var buttonBackgroundColor:UIColor = .darkGray

You can use the appearance proxy. 您可以使用外观代理。

[[UIView appearanceWhenContainedIn:[UIAlertController class], nil] setBackgroundColor:[UIColor blackColor]];

This seems to apply for all but the cancel action when presenting as an action sheet. 这似乎适用于除了作为动作表提交时的取消操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM