2

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?

Community
  • 1
  • 1
Christoper
  • 163
  • 1
  • 2
  • 10

3 Answers3

1

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")
Abhinav
  • 37,684
  • 43
  • 191
  • 309
1

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)
Abhishek Sharma
  • 3,283
  • 1
  • 13
  • 22
0

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.

R Menke
  • 8,183
  • 4
  • 35
  • 63
  • Is it okay to extend the UIAlertController? As in apple class reference states that you should not extend this class, https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/ – Christoper Oct 29 '15 at 04:13
  • @Christoper No it isn't ok. But it is possible. I don't know how this goes trough app review. If you don't present the alertcontroller animated you can just colour the background in the completion handler and then you don't need to sub class it. – R Menke Oct 29 '15 at 04:33