【问题标题】:How to change the background color of the UIAlertController?如何更改 UIAlertController 的背景颜色?
【发布时间】:2015-01-07 22:00:54
【问题描述】:

由于 iOS 8 中 UIActionSheet 的奇怪行为,我在 UIAlertController 中实现了 UIAction 作为按钮。我想改变 UIAlertController 的整个背景。但我找不到任何方法。

尝试过,

actionController.view.backgroundColor = [UIColor blackColor];

但没有帮助我。在这方面的任何意见都将是可观的。

提前致谢。

【问题讨论】:

  • 您好,亲爱的,根据您的问题,我创建了一个演示,它运行良好...我尝试使用黄色。它正在运行。

标签: ios objective-c uiactionsheet uialertcontroller


【解决方案1】:

您可以使用外观代理。

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

当显示为操作表时,这似乎适用于除取消操作之外的所有操作。

【讨论】:

  • 添加'yourAlertController.view.backgroundColor = [UIColor clearColor];'在您的代码使所有操作变黑之后。也取消操作。
  • 你失去了模糊效果,我看到按钮周围的伪影。不可用。
【解决方案2】:

你必须深入一些观点:

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

也许你想保持原来的圆角半径:

 alertContentView.layer.cornerRadius = 5;

对不起“Swifting”,但我不熟悉Objective-C。我希望那是相似的。

当然,更改动作的标题颜色也很重要。不幸的是,我不知道如何分别设置动作的颜色。但这就是,如何更改所有按钮文本颜色:

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

编辑:

自发布此答案以来,UIAlertController 的角半径已更改!替换这个:

 alertContentView.layer.cornerRadius = 5;

对此:

 actionContentView.layer.cornerRadius = 15

【讨论】:

  • 这里是 Objective C 版本:` UIView * firstView = alertController.view.subviews.firstObject; UIView * nextView = firstView.subviews.firstObject; nextView.backgroundColor = [UIColor greenColor];`
  • 这太棒了。它就像一个魅力,解决了我的问题。应该接受!
  • 如果你是 Swifting,分号是怎么回事?! :)
  • 这是什么版本的iOS?它似乎在 11.3 中不起作用
  • 在 iOS 13+ 中我们可以这样做:alertContentView.overrideUserInterfaceStyle = .dark
【解决方案3】:
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) {
        // ...
    }
}

【讨论】:

    【解决方案4】:

    我找到了一种 hack-ish 的方法。首先你需要一个扩展来让你在UIAlertController里面搜索UIVisualEffectView

    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
        }
    }
    

    重要提示:您必须在调用presentViewController 之后调用此函数,因为只有在加载视图控制器之后,视觉效果视图才会插入到位。然后你可以将与之关联的效果更改为暗模糊效果:

    self.presentViewController(actionController, animated: true, completion: nil)
    
    if let visualEffectView = actionController.view.searchVisualEffectsSubview()
    {
        visualEffectView.effect = UIBlurEffect(style: .Dark)
    }
    

    这是最终的结果:

    我真的很惊讶自己的效果如何!我认为这可能是苹果忘记添加的内容。另外,我还没有通过这种“黑客”的批准通过应用程序(这不是黑客,因为我们只使用公共 API),但我相信不会是个问题。

    【讨论】:

    • 这几乎行得通!不幸的是,在横向常规环境中,按钮并排排列的横向模式下,取消按钮仍然是白色的,因为它似乎没有视觉效果。
    • 目标 c 中的建议?
    【解决方案5】:

    Swift3

    与 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
        }
    

    【讨论】:

      【解决方案6】:

      也许你喜欢在黑暗模式下使用模糊效果。这是一个非常简单的方法:

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

      【讨论】:

      • 我最初将此标记为为我工作,但它没有。当我这样做时,actionSheets 工作正常(这是我试图解决的问题),但警报看起来与 actionSheets 不同。
      • 你是我的英雄。
      • 效果很好。在 swift 4.2 中,它可以更简洁地完成:UIVisualEffectView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).effect = UIBlurEffect(style: .dark)
      • 这不适用于取消按钮,仍然是白色。
      【解决方案7】:

      这是一个UIAlertController 扩展,适用于 iPad 和 iPhone。取消按钮会根据选择的 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
          }
      }
      

      还需要以下UIView 扩展:

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

      例子:

      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:

      【讨论】:

      • 您在通过 App Store 提交时遇到任何问题吗?
      • 没试过,但不违反苹果的任何规则。我们所做的只是使用公共类搜索子视图
      【解决方案8】:

      适用于 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
      

      .

      【讨论】:

        【解决方案9】:

        对于目标 - C 代码可能是这样的。

        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];
        

        【讨论】:

          【解决方案10】:

          我发现的最佳决定(两侧没有白点)

          Link to original answerVadim Akhmerov

          答案:

          继承UIAlertController更容易。

          这个想法是每次调用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
              }
          
          }
          

          用法:

          1. 创建警报控制器(现在使用 AlertController 而不是 UIAlertController)

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

          1. 在自定义类“AlertController”上设置背景颜色:

          var buttonBackgroundColor: UIColor = .darkGray

          【讨论】:

          • 这就是我一直在寻找的几个小时!你知道如何在选项之间保持细微的界限吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-11
          • 1970-01-01
          • 1970-01-01
          • 2019-03-07
          相关资源
          最近更新 更多