webentwicklung-frage-antwort-db.com.de

Wie kann man die Hintergrundfarbe des UIAlertControllers ändern?

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.

28
GJDK

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();

BEARBEITEN:

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
38
nischtname

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)
17

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:

demo picture

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 .

14
Bruno Philipe

für 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

 enter image description here .

7
Shakeel Ahmed

Swift3

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
    }
5
Leandro Jiao

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:

 enter image description here

iPad: 

 enter image description here

4
Mark Bourke
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
user2643679

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

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:

  1. Alert Controller erstellen (verwenden Sie jetzt AlertController anstelle von UIAlertController)

let testAlertController = AlertController (Titel: Null, Nachricht: Null, Vorzugstyp: .actionSheet)

  1. Legen Sie die Hintergrundfarbe für die benutzerdefinierte Klasse "AlertController" fest:

var buttonBackgroundColor: UIColor = .darkGray

0
Bandyliuk