UIAlertController更改操作表的“取消”按钮的背景颜色

时间:2017-06-17 06:51:33

标签: ios objective-c uialertcontroller

我正在尝试使用动作表样式创建UIAlertController,但我想将背景颜色更改为灰色。我已经能够找到一种方法来改变UIAlertController的背景颜色,但不能找到取消按钮。取消按钮是独立的,保持白色。

这是我现在的代码:

UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];

[alert addAction:[UIAlertAction actionWithTitle:@"Option 1" style:UIAlertActionStyleDefault handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:@"Option 2" style:UIAlertActionStyleDefault handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:@"Option 3" style:UIAlertActionStyleDefault handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:nil]];

[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];

UIView *firstSubview = alert.view.subviews.firstObject;
UIView *alertContentView = firstSubview.subviews.firstObject;

for (UIView *subSubView in alertContentView.subviews) {
    subSubView.backgroundColor = [UIColor darkGrayColor]; // Here you change background
}

alert.view.tintColor = [UIColor whiteColor];

[self.controller presentViewController:alert animated:YES completion:nil];

这给了我以下结果: Link

我访问了How to change the background color of the UIAlertController? ,但没有一个解决方案为“取消”按钮的背景设置了自定义颜色。

任何帮助将不胜感激!

5 个答案:

答案 0 :(得分:3)

如果您想要单独的取消按钮(UIAlertActionStyleCancel),则无法更改取消按钮的背景颜色。如果它是您的首选,那么您必须制作自己的自定义视图。或者,您只需添加标题为"取消"。

的默认操作

[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil]]

(但它不会给你一个单独的按钮)。

我调试了视图层次结构并找到了这个。 enter image description here

答案 1 :(得分:3)

有一个非常非常脏的解决方案,但它的工作原理。为此,我们将使用 UIAppearance

首先,我们需要为UIView准备一个特殊的私有扩展,以便能够更改它的子视图背景颜色。

fileprivate extension UIView {
    private struct AssociatedKey {
        static var subviewsBackgroundColor = "subviewsBackgroundColor"
    }

    @objc dynamic var subviewsBackgroundColor: UIColor? {
        get { 
          return objc_getAssociatedObject(self, &AssociatedKey.subviewsBackgroundColor) as? UIColor 
        }

        set {
          objc_setAssociatedObject(self,
                                   &AssociatedKey.subviewsBackgroundColor,
                                   newValue,
                                   .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
          subviews.forEach { $0.backgroundColor = newValue }
        }
    }
}

每次我们设置 subiewsBackgroundColor 值时,UIView将迭代它的子视图并为每个子视图设置一个新的背景颜色。

正如您在下面的答案中所看到的,在UIAlertController的层次结构中有一个名为 _UIAlertControlleriOSActionSheetCancelBackgroundView 的特殊UIView,它包含一个白色的子视图(用于取消按钮)

让我们尝试一下它并使用我们的属性来改变它的子视图颜色。我想这是一种私密的api。

if let cancelBackgroundViewType = NSClassFromString("_UIAlertControlleriOSActionSheetCancelBackgroundView") as? UIView.Type {
    cancelBackgroundViewType.appearance().subviewsBackgroundColor = .red
}

将此代码放在AppDelegate的didFinishLaunching或专用类中。 就是这样。现在,您可以在红色背景上看到取消按钮。在iOS 11上测试。

答案 2 :(得分:3)

您不能更改默认取消样式按钮的颜色。您需要为“取消”按钮创建一个自定义视图控制器,并将其设置为“取消警报”操作的内容视图控制器。这样可以将取消按钮分开保存

enter image description here

let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

alertController.addAction(UIAlertAction(title: "Option 1", style: .default, handler: nil))
alertController.addAction(UIAlertAction(title: "Option 2", style: .default, handler: nil))
alertController.addAction(UIAlertAction(title: "Option 3", style: .default, handler: nil))

alertController.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: nil))

if let firstSubview = alertController.view.subviews.first, let alertContentView = firstSubview.subviews.first {
    for view in alertContentView.subviews {
        view.backgroundColor = .darkGray
    }
}

alertController.view.tintColor = .white

let cancelButtonViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CancelButtonViewController")
let cancelAction = UIAlertAction(title: "", style: .cancel, handler: nil)
cancelAction.setValue(cancelButtonViewController, forKey: "contentViewController")

alertController.addAction(cancelAction)

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

enter image description here

答案 3 :(得分:0)

我现在得到了解决方案。我创建了示例项目,并为您的问题解决了问题,我得到了它。

ViewController.h

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];

    [alert addAction:[UIAlertAction actionWithTitle:@"Option 1" style:UIAlertActionStyleDefault handler:nil]];
    [alert addAction:[UIAlertAction actionWithTitle:@"Option 2" style:UIAlertActionStyleDefault handler:nil]];
    [alert addAction:[UIAlertAction actionWithTitle:@"Option 3" style:UIAlertActionStyleDefault handler:nil]];
    [alert addAction:[UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:nil]];

    [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];

    UIView *subView = alert.view.subviews.lastObject; //firstObject
    UIView *alertContentView = subView.subviews.lastObject; //firstObject
    [alertContentView setBackgroundColor:[UIColor darkGrayColor]];
    alertContentView.layer.cornerRadius = 5;
    [self presentViewController:alert animated:YES completion:nil];
    alert.view.tintColor = [UIColor darkGrayColor];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

参见输出

enter image description here

答案 4 :(得分:0)

在混合的Objective-C / Swift项目中,我使用了answermbryzinski,并且能够像这样修改Objective-C的“取消”按钮背景颜色:

((UIView *)[NSClassFromString(@"_UIAlertControlleriOSActionSheetCancelBackgroundView")
 appearance]).subviewsBackgroundColor = [UIColor yourBackgroundColor];

我将UIView扩展作为.swift文件包含在项目中,并且必须删除 fileprivate 关键字:

extension UIView {
    private struct AssociatedKey {
        static var subviewsBackgroundColor = "subviewsBackgroundColor"
    }
    @objc dynamic var subviewsBackgroundColor: UIColor? {
    ...

此外,还需要将桥接标头导入使用扩展名的文件中:

#import "{Your Project's name}-Swift.h"

修改UIAlertController的背景和文本颜色是一种用于实现深色主题的快速方法(确实很脏)。 圆角附近有一些细微的瑕疵,随着背景颜色变深,这些瑕疵变得更加明显。特别是在iPad上,这些痕迹非常明显。

正确的解决方案可能是使用自定义警报控制器。 (尚未找到一种看上去与普通股票相似的股票。)