Christoper
Christoper

Reputation: 173

Change background color of title (only) in UIAlertController

I found the following code in How to change the background color of the UIAlertController? to change the background color of a UIAlertView:

let subview = dialog.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
subview.subviews.top!
alertContentView.backgroundColor = UIColor.whiteColor()

However, it changes the background color of the entire view. How can I change only the background color of the title?

Upvotes: 2

Views: 1528

Answers (3)

R Menke
R Menke

Reputation: 8391

Sample project -> Contains latest code

Step one:

Find a subview that has the right frame!

This little function will return the frame and address of all nested subviews.

We are looking for a subview that has a height that is smaller than that of the UIAlertController and has an Origin of 0,0. Height of my alertController was 128

func subViewStack(view:UIView, levels: [Int]) {

    var currentLevels = levels
    currentLevels.append(0)

    for i in 0..<view.subviews.count {

        currentLevels[currentLevels.count - 1] = i

        let subView = view.subviews[i]
        print(subView.frame, "depth:", currentLevels)
        subViewStack(subView, levels: currentLevels)

    }

}

This prints stuff like this:

(0.0, 0.0, 270.0, 128.0) depth: [0, 0]

//frame - firstsubview - firstsubview

This might be a good candidate:

(0.0, 0.0, 270.0, 84.0) depth: [0, 1, 0, 0]
//frame - firstsubview - secondsubiew - firstsubview - firstsubview

This translates to this:

print(alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].frame)
// prints (0.0, 0.0, 270.0, 84.0) -> Bingo!

Step two:

Color that subview!

alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].backgroundColor = UIColor.redColor()

If you set the colour before presenting the alertController it will crash. Setting it in the completionHandler works.

presentViewController(alertController, animated: true) { () -> Void in

    self.subViewStack(alertController.view, levels: [])
    print(alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].frame)
    alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].backgroundColor = UIColor.redColor()

}

Step three:

Make it safe! If they ever change anything to the stack this will prevent your app from crashing. Your view might not be coloured but a crash is worse.

Extend UIView to be able to fetch subviews with one of the addresses we printed earlier. Use guardor if let to prevent accessing non-existent subviews.

extension UIView {

    // use the printed addresses to access the views. This is safe even if the UIView changes in an update.
    func getSubView(withAddress address:[Int]) -> UIView? {

        var currentView : UIView = self

        for index in address {

            guard currentView.subviews.count > index else {
                return nil
            }
            currentView = currentView.subviews[index]

        }
        return currentView
    }
}

Step four:

Since it is not allowed to subclass UIAlertController we might try to extend it. This won't give you access to viewDidAppear so you can't display the UIAlertController animated.

protocol CustomAlert {

    var view : UIView! { get }

}

extension CustomAlert {

    func titleBackgroundColor(color:UIColor) {

        if view == nil {
            return
        }

        if let titleBackground = view.getSubView(withAddress: [0, 1, 0, 0]) {
            titleBackground.backgroundColor = color
        }
    }
}

extension UIAlertController : CustomAlert {

}

This gives you both the method to find any subviews you might want to alter and a way to add a custom function for it to that class. Without subclassing.

Call titleBackgroundColor in the completionHandler of presentViewController to set the color.

Upvotes: 0

Abhishek Sharma
Abhishek Sharma

Reputation: 3283

try with following its works for me.

 let confirmAlert = UIAlertController(title: "Application Name", message: "This is demo message.", preferredStyle: .Alert)

        let attributedString = NSAttributedString(string: "Application Name", attributes: [
            NSFontAttributeName : UIFont.systemFontOfSize(13),
            NSForegroundColorAttributeName : UIColor.greenColor()
            ])
        let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
        confirmAlert.addAction(defaultAction)

        confirmAlert.setValue(attributedString, forKey: "attributedTitle")
        UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(confirmAlert, animated: true, completion: nil)

Upvotes: 1

Abhinav
Abhinav

Reputation: 38152

Try this out:

let alertController = UIAlertController(title: "", message: "myMessage", preferredStyle: .Alert)

let attributedString = NSAttributedString(string: "myTitle", attributes: [
    NSFontAttributeName : UIFont.systemFontOfSize(15),
    NSForegroundColorAttributeName : UIColor.redColor()
    ])

alertController.setValue(attributedString, forKey: "attributedTitle")

Upvotes: 1

Related Questions