Aufgrund des merkwürdigen Verhaltens von UIActionSheet in iOS 8 habe ich UIAlertController mit UIAction als Schaltflächen darin implementiert. Ich möchte den gesamten Hintergrund des UIAlertControllers ändern. Aber ich finde keine Möglichkeiten, dies zu tun.
Versucht sogar mit,
actionController.view.backgroundColor = [UIColor blackColor];
Hat mir aber nicht geholfen. Etwaige diesbezügliche Eingaben werden spürbar sein.
Danke im Voraus.
Sie müssen einige Ansichten tiefer gehen:
let subview = actionController.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
alertContentView.backgroundColor = UIColor.blackColor()
Und vielleicht möchten Sie den ursprünglichen Eckenradius beibehalten:
alertContentView.layer.cornerRadius = 5;
Entschuldigung für das "Swifting", aber ich bin mit Objective-C nicht vertraut. Ich hoffe das ist ähnlich.
Natürlich ist es auch wichtig, die Titelfarbe der Aktionen zu ändern. Leider weiß ich nicht, wie ich die Farbe der Aktionen separat einstellen kann. Aber so ändern Sie alle Textfarben für Schaltflächen:
actionController.view.tintColor = UIColor.whiteColor();
Der Eckenradius des UIAlertController hat sich geändert, seit diese Antwort veröffentlicht wurde! Ersetzen Sie dies:
alertContentView.layer.cornerRadius = 5;
dazu:
actionContentView.layer.cornerRadius = 15
vielleicht mögen Sie den Unschärfe-Effekt im dunklen Modus. Hier ist ein sehr einfacher Weg, dies zu erhalten:
UIVisualEffectView.appearance(whenContainedInInstancesOf: [UIAlertController.classForCoder() as! UIAppearanceContainer.Type]).effect = UIBlurEffect(style: .dark)
Ich habe einen hackistischen Weg gefunden, es zu tun. Als Erstes benötigen Sie eine Erweiterung, mit der Sie nach der UIVisualEffectView
in der UIAlertController
suchen können:
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
}
}
Wichtig : Sie müssen diese Funktion after aufrufen, um presentViewController
aufzurufen, denn erst nach dem Laden des View-Controllers wird die visuelle Effektansicht eingefügt. Dann können Sie den damit verbundenen Effekt in einen dunklen Unschärfeeffekt ändern:
self.presentViewController(actionController, animated: true, completion: nil)
if let visualEffectView = actionController.view.searchVisualEffectsSubview()
{
visualEffectView.effect = UIBlurEffect(style: .Dark)
}
Und das ist das Endergebnis:
Ich bin ehrlich überrascht, wie gut es funktioniert! Ich denke, das hat Apple wahrscheinlich vergessen, hinzuzufügen. Außerdem habe ich noch nicht mit diesem "Hack" eine App durch Zustimmung bestanden (es ist kein Hack, weil wir nur öffentliche APIs verwenden), aber ich bin zuversichtlich, dass es kein Problem geben wird .
Steigen Sie in eine weitere Schicht mit Swift2 ein
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
}
Hier ist eine Erweiterung von UIAlertController
, die auf iPad und iPhone funktioniert. Die Schaltfläche "Abbrechen" ändert sich automatisch von einer dunklen Farbe zu Weiß, je nachdem, welcher BlurStyle ausgewählt ist:
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
}
}
Die folgende Erweiterung von UIView
wird ebenfalls benötigt:
extension UIView {
var recursiveSubviews: [UIView] {
var subviews = self.subviews.flatMap({$0})
subviews.forEach { subviews.append(contentsOf: $0.recursiveSubviews) }
return subviews
}
}
Beispiel:
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:
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) {
// ...
}
}
Für Objective - C-Code kann wie sein.
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];
Die beste Entscheidung, die ich gefunden habe (ohne weiße Flecken an den Seiten)
Link zur Originalantwort von Vadim Akhmerov
Antworten:
Es ist einfacher, UIAlertController
zu unterteilen.
Die Idee ist, bei jedem Aufruf von viewDidLayoutSubviews
die Ansichtshierarchie zu durchlaufen, den Effekt für UIVisualEffectView
zu entfernen und ihre backgroundColor
zu aktualisieren:
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
}
}
Verwendungszweck:
let testAlertController = AlertController (Titel: Null, Nachricht: Null, Vorzugstyp: .actionSheet)
var buttonBackgroundColor: UIColor = .darkGray