【问题标题】:UIAlertController change background color of Cancel button for action sheetUIAlertController 更改操作表的取消按钮的背景颜色
【发布时间】:2017-06-17 06:51:32
【问题描述】:

我正在尝试使用操作表样式创建 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? ,但没有一个解决方案为“取消”按钮的背景提供自定义颜色。

任何帮助将不胜感激!

【问题讨论】:

  • 你想改变取消按钮的背景颜色吗?
  • 查看我的编码 我将取消按钮颜色更改为深灰色。
  • 我希望取消按钮具有深灰色背景色和白色文本。您的代码似乎没有这样做,而是相反:您的取消按钮的背景颜色是白色,而您的文本颜色是灰色

标签: ios objective-c uialertcontroller


【解决方案1】:

有一个非常肮脏的解决方案,但它有效。为此,我们将使用 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 上测试。

【讨论】:

  • 如何到达_UIVisualEffectSubview?
  • _ 为前缀的类是 iOS 的私有类,调整非公共类可能会导致应用被拒绝,或者在任何更新破坏应用程序的 UI 时都可以更改非公共内部类。
【解决方案2】:

您无法更改默认取消按钮样式的颜色。您需要为取消按钮创建一个自定义视图控制器,并将其设置为取消警报操作的内容视图控制器。这种方式将取消按钮单独保留

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)

【讨论】:

  • 控制器约束被破坏。如果您有超过 10 个项目,则取消按钮会与最后一个项目重叠
  • @geek1706 取消按钮与最后一项重叠
【解决方案3】:

如果你想要一个单独的取消按钮(UIAlertActionStyleCancel),你不能改变取消按钮的背景颜色。如果这是您的优先事项,那么您必须制作自己的自定义视图。或者,您可以简单地添加一个标题为“取消”的默认操作。

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

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

我已经调试了视图层次结构并找到了这个。

【讨论】:

    【解决方案4】:

    我在我的 Objective-C / Swift 混合项目中使用了 mbryzinskianswer,并且能够像这样修改来自 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 上,伪影非常明显。

    正确的解决方案可能是使用自定义警报控制器。 (还没有找到一个看起来最像股票的。)

    【讨论】:

      【解决方案5】:

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

      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
      

      查看输出

      【讨论】:

      • 我认为您没有正确理解我的问题。取消按钮的背景颜色仍然是白色,而您的文本现在是灰色的。我需要相反的事情发生
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-01
      • 2017-02-04
      • 1970-01-01
      • 2015-01-07
      • 2021-06-22
      相关资源
      最近更新 更多