UIAlertController custom font, size, color
Asked Answered
W

24

128

I am using new UIAlertController for showing alerts. I have this code:

// nil titles break alert interface on iOS 8.0, so we'll be using empty strings
UIAlertController *alert = [UIAlertController alertControllerWithTitle: title == nil ? @"": title message: message preferredStyle: UIAlertControllerStyleAlert];


UIAlertAction *defaultAction = [UIAlertAction actionWithTitle: cancelButtonTitle style: UIAlertActionStyleCancel handler: nil];

[alert addAction: defaultAction];

UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootViewController presentViewController:alert animated:YES completion:nil];

Now I want to change title and message font, color, size and so. What's best way to do this?

Edit: I should insert whole code. I created category for UIView that I could show right alert for iOS version.

@implementation UIView (AlertCompatibility)

+( void )showSimpleAlertWithTitle:( NSString * )title
                          message:( NSString * )message
                cancelButtonTitle:( NSString * )cancelButtonTitle
{
    float iOSVersion = [[UIDevice currentDevice].systemVersion floatValue];
    if (iOSVersion < 8.0f)
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle: title
                                                        message: message
                                                       delegate: nil
                                              cancelButtonTitle: cancelButtonTitle
                                              otherButtonTitles: nil];
        [alert show];
    }
    else
    {
        // nil titles break alert interface on iOS 8.0, so we'll be using empty strings
        UIAlertController *alert = [UIAlertController alertControllerWithTitle: title == nil ? @"": title
                                                                       message: message
                                                                preferredStyle: UIAlertControllerStyleAlert];


        UIAlertAction *defaultAction = [UIAlertAction actionWithTitle: cancelButtonTitle
                                                                style: UIAlertActionStyleCancel
                                                              handler: nil];

        [alert addAction: defaultAction];

        UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
        [rootViewController presentViewController:alert animated:YES completion:nil];
    }
}
Wald answered 20/10, 2014 at 7:45 Comment(1)
DISCLAIMER: To anyone who's reading the below answers. Apple will reject your app(s). If you tend use any private Api(s). And in the below answers THAT'S WHAT'S HAPPENING..Papillose
B
101

Not sure if this is against private APIs/properties but using KVC works for me on ios8

UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"Dont care what goes here, since we're about to change below" message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
NSMutableAttributedString *hogan = [[NSMutableAttributedString alloc] initWithString:@"Presenting the great... Hulk Hogan!"];
[hogan addAttribute:NSFontAttributeName
              value:[UIFont systemFontOfSize:50.0]
              range:NSMakeRange(24, 11)];
[alertVC setValue:hogan forKey:@"attributedTitle"];



UIAlertAction *button = [UIAlertAction actionWithTitle:@"Label text" 
                                        style:UIAlertActionStyleDefault
                                        handler:^(UIAlertAction *action){
                                                    //add code to make something happen once tapped
}];
UIImage *accessoryImage = [UIImage imageNamed:@"someImage"];
[button setValue:accessoryImage forKey:@"image"];

For the record, it is possible to change alert action's font as well, using those private APIs. Again, it may get you app rejected, I have not yet tried to submit such code.

let alert = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)

let action = UIAlertAction(title: "Some title", style: .Default, handler: nil)
let attributedText = NSMutableAttributedString(string: "Some title")

let range = NSRange(location: 0, length: attributedText.length)
attributedText.addAttribute(NSKernAttributeName, value: 1.5, range: range)
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "ProximaNova-Semibold", size: 20.0)!, range: range)

alert.addAction(action)

presentViewController(alert, animated: true, completion: nil)

// this has to be set after presenting the alert, otherwise the internal property __representer is nil
guard let label = action.valueForKey("__representer")?.valueForKey("label") as? UILabel else { return }
label.attributedText = attributedText

For Swift 4.2 in XCode 10 and up the last 2 lines are now:

guard let label = (action!.value(forKey: "__representer")as? NSObject)?.value(forKey: "label") as? UILabel else { return }
        label.attributedText = attributedText
Banian answered 23/10, 2014 at 14:34 Comment(13)
It's working. attributedTitle for title and attributedMessage for message. Not sure if it's best solution but for now it's good enough for me.Wald
what all customization we can add on UIAlertController buttons??Overtone
How did you find the key attributeTitle? Understandably, attributeMessage is also a key but how did you find these? Is there a way I can look these up in some header files.Lema
Thanks! I have a small question — one could use custom fonts and colors with the attribute tile and message in UIAlertController. How can one do the same with UIAlertAction?Lema
@Lema i don't think you can (nor have i needed to or tried to)....looking at github.com/nst/iOS-Runtime-Headers/blob/… maybe you can try messing with the image key and use a pre-rendered image, instead of text? total shot in the dark....Banian
I have a font scheme throughout the app, so changing the font for those labels seems quite necessary. Thanks for the help though!Lema
@Lema - Did you ever find a solution for customizing the font for UIAlertAction?Janka
Nope. But I haven't seen the updates in iOS 9. Maybe it's there. :XLema
@Lema - I haven't found anything so far. We are still stuck dealing with strings for the UIAlertAction title, which I don't think you can customize the font for. #33533441Janka
As far as changing font on theUIAlertAction it is possible but defiantly not recommended. In order to change the font/BGColor you have to subclass and Apple clearly states in the docs that you aren't supposed to do this and could result in your app being rejected from the app storeAnthia
can't emphasize the importance of attributedMessage as mentioned by @LiborZapletalMilissamilissent
I hope none of you are planning on releasing this to the app store as it uses private APIs. Seriously, I have no idea why these answers are ever accepted on Stackoverflow when they're not really 'answers'. These are hacks that you may or may not get away with publishing in the application store.Merat
For case of releasing app on app store, some of the private api uses are allowed by Apple, but it should not use the apis which may harm or affects the system/privacy of user. So, Probably this answer may be accepted by many people due to this only. And probably it might not be affecting on app store. Can someone who have used this, can they confirm that their app is not rejected?Monochasium
I
69

You can change the button color by applying a tint color to an UIAlertController.

On iOS 9, if the window tint color was set to a custom color, you have to apply the tint color right after presenting the alert. Otherwise the tint color will be reset to your custom window tint color.

// In your AppDelegate for example:
window?.tintColor = UIColor.redColor()

// Elsewhere in the App:
let alertVC = UIAlertController(title: "Title", message: "message", preferredStyle: .Alert)
alertVC.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
alertVC.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))

// Works on iOS 8, but not on iOS 9
// On iOS 9 the button color will be red
alertVC.view.tintColor = UIColor.greenColor()

self.presentViewController(alert, animated: true, completion: nil)

// Necessary to apply tint on iOS 9
alertVC.view.tintColor = UIColor.greenColor()
Insipience answered 17/9, 2015 at 17:53 Comment(4)
To clarify, setting the tintColor after presenting the controller works on both iOS 8 and 9, so it is not necessary to set it twice.Edea
Thanks for adding a Swift answer and a workaround for this issue in iOS 9.Janka
When i tap and drag my finger down, it will again goes to default colour. Any idea?Gooseneck
This is really the only decent answer here.Merat
S
53

You can change color of button text using this code:

alertC.view.tintColor = your color;

Maybe this will help you.

Sabin answered 20/10, 2014 at 8:3 Comment(5)
@esilver did you manage to find a solution that works with iOS9?Countrywide
I did not. I created a bug report with Apple, #22391695.Tracietracing
More informations about this. It seems that when you scroll in a long list items, the one you touch to scroll becomes blue...Diorama
None of this work on UIAlertController in iOS9 and 9.1.. Dont know what Apple guys are upto... Need to manually change the window tint every time an alert controller is called and change it back in the handler.Geof
It works with iOS 9.3, unless you touch up outiside: comes back to system blueLugubrious
P
39

In Xcode 8 Swift 3.0

@IBAction func touchUpInside(_ sender: UIButton) {

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

    //to change font of title and message.
    let titleFont = [NSFontAttributeName: UIFont(name: "ArialHebrew-Bold", size: 18.0)!]
    let messageFont = [NSFontAttributeName: UIFont(name: "Avenir-Roman", size: 12.0)!]

    let titleAttrString = NSMutableAttributedString(string: "Title Here", attributes: titleFont)
    let messageAttrString = NSMutableAttributedString(string: "Message Here", attributes: messageFont)

    alertController.setValue(titleAttrString, forKey: "attributedTitle")
    alertController.setValue(messageAttrString, forKey: "attributedMessage")

    let action1 = UIAlertAction(title: "Action 1", style: .default) { (action) in
        print("\(action.title)")
    }

    let action2 = UIAlertAction(title: "Action 2", style: .default) { (action) in
        print("\(action.title)")
    }

    let action3 = UIAlertAction(title: "Action 3", style: .default) { (action) in
        print("\(action.title)")
    }

    let okAction = UIAlertAction(title: "Ok", style: .default) { (action) in
        print("\(action.title)")
    }

    alertController.addAction(action1)
    alertController.addAction(action2)
    alertController.addAction(action3)
    alertController.addAction(okAction)

    alertController.view.tintColor = UIColor.blue
    alertController.view.backgroundColor = UIColor.black
    alertController.view.layer.cornerRadius = 40

    present(alertController, animated: true, completion: nil)

}

Output

UIAlertController custom font, size and color

Principal answered 23/12, 2016 at 10:7 Comment(1)
Sorry bro, this is start up. If required in feature i will inform to you...Patentor
P
25

A Swift translation of the @dupuis2387 answer. Worked out the syntax to set the UIAlertController title's color and font via KVC using the attributedTitle key.

let message = "Some message goes here."
let alertController = UIAlertController(
    title: "", // This gets overridden below.
    message: message,
    preferredStyle: .Alert
)
let okAction = UIAlertAction(title: "OK", style: .Cancel) { _ -> Void in
}
alertController.addAction(okAction)

let fontAwesomeHeart = "\u{f004}"
let fontAwesomeFont = UIFont(name: "FontAwesome", size: 17)!
let customTitle:NSString = "I \(fontAwesomeHeart) Swift" // Use NSString, which lets you call rangeOfString()
let systemBoldAttributes:[String : AnyObject] = [ 
    // setting the attributed title wipes out the default bold font,
    // so we need to reconstruct it.
    NSFontAttributeName : UIFont.boldSystemFontOfSize(17)
]
let attributedString = NSMutableAttributedString(string: customTitle as String, attributes:systemBoldAttributes)
let fontAwesomeAttributes = [
    NSFontAttributeName: fontAwesomeFont,
    NSForegroundColorAttributeName : UIColor.redColor()
]
let matchRange = customTitle.rangeOfString(fontAwesomeHeart)
attributedString.addAttributes(fontAwesomeAttributes, range: matchRange)
alertController.setValue(attributedString, forKey: "attributedTitle")

self.presentViewController(alertController, animated: true, completion: nil)

enter image description here

Proliferate answered 21/3, 2016 at 16:30 Comment(6)
What about "OK" button? Can we customize it?Castlereagh
@HassanTaleb I haven't found a great way to customize the button. You can set the tintColor on the view or via appearanceWhenContainedIn, but the tint goes away as soon as you touch it. Still searching for answers though.Proliferate
@AbdulMomenعبدالمؤمن What error message are you seeing? The code snippet assumes FontAwesome is already set up.Proliferate
@RobertChen didn't recognize attributedTitle in alertController.setValue(attributedString, forKey: "attributedTitle")Resignation
@RobertChen to solve the issue just put the tint after : self.presentViewController(alertController, animated: true, completion: nil) , can we change the font of the button "OK"?Castlereagh
Isn't this considered a private api?Backache
A
22

Swift 5 and 5.1. Create a separate file and put UIAlertController Customization code there

import Foundation
import  UIKit

extension UIAlertController {

  //Set background color of UIAlertController
  func setBackgroudColor(color: UIColor) {
    if let bgView = self.view.subviews.first,
      let groupView = bgView.subviews.first,
      let contentView = groupView.subviews.first {
      contentView.backgroundColor = color
    }
  }

  //Set title font and title color
  func setTitle(font: UIFont?, color: UIColor?) {
    guard let title = self.title else { return }
    let attributeString = NSMutableAttributedString(string: title)//1
    if let titleFont = font {
      attributeString.addAttributes([NSAttributedString.Key.font : titleFont],//2
        range: NSMakeRange(0, title.utf8.count))
    }
    if let titleColor = color {
      attributeString.addAttributes([NSAttributedString.Key.foregroundColor : titleColor],//3
        range: NSMakeRange(0, title.utf8.count))
    }
    self.setValue(attributeString, forKey: "attributedTitle")//4
  }

  //Set message font and message color
  func setMessage(font: UIFont?, color: UIColor?) {
    guard let title = self.message else {
      return
    }
    let attributedString = NSMutableAttributedString(string: title)
    if let titleFont = font {
      attributedString.addAttributes([NSAttributedString.Key.font : titleFont], range: NSMakeRange(0, title.utf8.count))
    }
    if let titleColor = color {
      attributedString.addAttributes([NSAttributedString.Key.foregroundColor : titleColor], range: NSMakeRange(0, title.utf8.count))
    }
    self.setValue(attributedString, forKey: "attributedMessage")//4
  }

  //Set tint color of UIAlertController
  func setTint(color: UIColor) {
    self.view.tintColor = color
  }
}

Now On any action Show Alert

  func tapShowAlert(sender: UIButton) {
    let alertController = UIAlertController(title: "Alert!!", message: "This is custom alert message", preferredStyle: .alert)
    // Change font and color of title
    alertController.setTitle(font: UIFont.boldSystemFont(ofSize: 26), color: UIColor.yellow)
    // Change font and color of message
    alertController.setMessage(font: UIFont(name: "AvenirNextCondensed-HeavyItalic", size: 18), color: UIColor.red)
    // Change background color of UIAlertController
    alertController.setBackgroudColor(color: UIColor.black)
    let actnOk = UIAlertAction(title: "Ok", style: .default, handler: nil)
    let actnCancel = UIAlertAction(title: "Cancel", style: .default, handler: nil)
    alertController.addAction(actnOk)
    alertController.addAction(actnCancel)
    self.present(alertController, animated: true, completion: nil)
  }

Result

enter image description here

Archaimbaud answered 26/5, 2019 at 10:13 Comment(4)
are we accessing any private Api's over here .? have you released any app with these many custom alert properties?Papillose
@YashBedi it's using private APIs and Apple might reject your app for "non-public API" usage. No, I haven't released any app.Archaimbaud
This is mentioned on Apple developer site -> Important The UIAlertController class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.Archaimbaud
@Darkglow Please mention the error. I am able to build successfully the same code with swift 5.1Archaimbaud
Z
14

Use UIAppearance protocol. Example for setting a font - create a category to extend UILabel:

@interface UILabel (FontAppearance)
@property (nonatomic, copy) UIFont * appearanceFont UI_APPEARANCE_SELECTOR;
@end


@implementation UILabel (FontAppearance)

-(void)setAppearanceFont:(UIFont *)font {
    if (font)
        [self setFont:font];
}

-(UIFont *)appearanceFont {
    return self.font;
}

@end

And its usage:

UILabel * appearanceLabel = [UILabel appearanceWhenContainedIn:UIAlertController.class, nil];
[appearanceLabel setAppearanceFont:[UIFont boldSystemFontOfSize:10]]; //for example

Tested and working with style UIAlertControllerStyleActionSheet, but I guess it will work with UIAlertControllerStyleAlert too.

P.S. Better check for class availability instead of iOS version:

if ([UIAlertController class]) {
    // UIAlertController code (iOS 8)
} else {
    // UIAlertView code (pre iOS 8)
}
Zebapda answered 20/10, 2014 at 10:53 Comment(3)
It's working but this way I can't have different size for message and for title.Wald
This works but when an action is clicked, the font reverts back to the original size? Does this happen for you?Cathiecathleen
I have the same problem @Cathiecathleen and I haven't found a way to deal with it.. have you?Chanteuse
A
12

Use UIAppearance protocol. Do more hacks with appearanceFont to change font for UIAlertAction.

Create a category for UILabel

UILabel+FontAppearance.h

@interface UILabel (FontAppearance)

@property (nonatomic, copy) UIFont * appearanceFont UI_APPEARANCE_SELECTOR;

@end

UILabel+FontAppearance.m

@implementation UILabel (FontAppearance)

- (void)setAppearanceFont:(UIFont *)font
{
    if (self.tag == 1001) {
        return;
    }

    BOOL isBold = (self.font.fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold);
    const CGFloat* colors = CGColorGetComponents(self.textColor.CGColor);

    if (self.font.pointSize == 14) {
        // set font for UIAlertController title
        self.font = [UIFont systemFontOfSize:11];
    } else if (self.font.pointSize == 13) {
        // set font for UIAlertController message
        self.font = [UIFont systemFontOfSize:11];
    } else if (isBold) {
        // set font for UIAlertAction with UIAlertActionStyleCancel
        self.font = [UIFont systemFontOfSize:12];
    } else if ((*colors) == 1) {
        // set font for UIAlertAction with UIAlertActionStyleDestructive
        self.font = [UIFont systemFontOfSize:13];
    } else {
        // set font for UIAlertAction with UIAlertActionStyleDefault
        self.font = [UIFont systemFontOfSize:14];
    }
    self.tag = 1001;
}

- (UIFont *)appearanceFont
{
    return self.font;
}

@end

Usage:

add

[[UILabel appearanceWhenContainedIn:UIAlertController.class, nil] setAppearanceFont:nil];

in AppDelegate.m to make it work for all UIAlertController.

Andean answered 26/5, 2015 at 16:14 Comment(3)
The title in iOS 8.3 is 13pt and bold so I changed the condition to if (self.font.pointSize == 13 && isBold) {Anemochore
You mentioned changing the font for UIAlertAction. But as far as I can tell, UIAlertAction does not use a UILabel. It uses an NSString. github.com/nst/iOS-Runtime-Headers/blob/… I don't know how you could customize the font for an NSString.Janka
UIAlertAction is not a view class at all. It is an abstract class describing the action. The view itself is then generated inside UIAlertController. You therefore set the appearance contained in UIAlertController.Stultz
M
10

I'm using it.

[[UIView appearanceWhenContainedIn:[UIAlertController class], nil] setTintColor:[UIColor blueColor]];

Add one line (AppDelegate) and works for all UIAlertController.

Minette answered 28/2, 2015 at 19:45 Comment(1)
As this is now deprecated, use [[UIView appearanceWhenContainedInInstancesOfClasses:@[[UIAlertController class]]] setTintColor:newColor]; insteadTubercle
P
9

Swift 4

Example of custom font on the title. Same things for other components such as message or actions.

    let titleAttributed = NSMutableAttributedString(
            string: Constant.Strings.cancelAbsence, 
            attributes: [NSAttributedStringKey.font:UIFont(name:"FONT_NAME",size: FONT_SIZE)]
    )

    let alertController = UIAlertController(
        title: "",
        message: "",
        preferredStyle: UIAlertControllerStyle.YOUR_STYLE
    )

    alertController.setValue(titleAttributed, forKey : "attributedTitle")
    present(alertController, animated: true, completion: nil)
Pedanticism answered 21/2, 2018 at 14:27 Comment(0)
B
6

You can use an external library like PMAlertController without using workaround, where you can substitute Apple's uncustomizable UIAlertController with a super customizable alert.

Compatible with Xcode 8, Swift 3 and Objective-C

PMAlertController example


Features:

  • [x] Header View
  • [x] Header Image (Optional)
  • [x] Title
  • [x] Description message
  • [x] Customizations: fonts, colors, dimensions & more
  • [x] 1, 2 buttons (horizontally) or 3+ buttons (vertically)
  • [x] Closure when a button is pressed
  • [x] Text Fields support
  • [x] Similar implementation to UIAlertController
  • [x] Cocoapods
  • [x] Carthage
  • [x] Animation with UIKit Dynamics
  • [x] Objective-C compatibility
  • [x] Swift 2.3 & Swift 3 support
Bacillary answered 3/7, 2017 at 9:50 Comment(2)
Does PMAlertController allow for word wrap when the text is long in the action buttons?Chaotic
@Chaotic consider that the action button is a subclass of UIButton. Something like that actionButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping works well.Bacillary
P
5

In Swift 4.1 and Xcode 10

//Displaying alert with multiple actions and custom font ans size
let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)

let titFont = [NSAttributedStringKey.font: UIFont(name: "ArialHebrew-Bold", size: 15.0)!]
let msgFont = [NSAttributedStringKey.font: UIFont(name: "Avenir-Roman", size: 13.0)!]

let titAttrString = NSMutableAttributedString(string: "Title Here", attributes: titFont)
let msgAttrString = NSMutableAttributedString(string: "Message Here", attributes: msgFont)

alert.setValue(titAttrString, forKey: "attributedTitle")
alert.setValue(msgAttrString, forKey: "attributedMessage")

let action1 = UIAlertAction(title: "Action 1", style: .default) { (action) in
    print("\(String(describing: action.title))")
}

let action2 = UIAlertAction(title: "Action 2", style: .default) { (action) in
    print("\(String(describing: action.title))")
}

let okAction = UIAlertAction(title: "Ok", style: .default) { (action) in
    print("\(String(describing: action.title))")
}
alert.addAction(action1)
alert.addAction(action2)
alert.addAction(okAction)

alert.view.tintColor = UIColor.blue
alert.view.layer.cornerRadius = 40
// //If required background colour 
// alert.view.backgroundColor = UIColor.white

DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})
Patentor answered 28/8, 2018 at 5:23 Comment(1)
your answer needs a update , self.present(alertController, animated: true) or self.present(alert, animated: true).Papillose
K
5

Here is an extension for Swift 4.1 and Xcode 9.4.1:

extension UIAlertController{

func addColorInTitleAndMessage(color:UIColor,titleFontSize:CGFloat = 18, messageFontSize:CGFloat = 13){

    let attributesTitle = [NSAttributedStringKey.foregroundColor: color, NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: titleFontSize)]
    let attributesMessage = [NSAttributedStringKey.foregroundColor: color, NSAttributedStringKey.font: UIFont.systemFont(ofSize: messageFontSize)]
    let attributedTitleText = NSAttributedString(string: self.title ?? "", attributes: attributesTitle)
    let attributedMessageText = NSAttributedString(string: self.message ?? "", attributes: attributesMessage)

    self.setValue(attributedTitleText, forKey: "attributedTitle")
    self.setValue(attributedMessageText, forKey: "attributedMessage")

}}
Kocher answered 14/9, 2018 at 1:46 Comment(0)
M
4

I just completed a replacement for UIAlertController. This is the only sensible way to go, I think:


Old

Here's my method in Swift which mashes up a lot of information from answers here

func changeAlert(alert: UIAlertController, backgroundColor: UIColor, textColor: UIColor, buttonColor: UIColor?) {
    let view = alert.view.firstSubview().firstSubview()
    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.boldSystemFontOfSize(17)])
    alert.setValue(titleAttributed, forKey: "attributedTitle")


    let messageAttributed = NSMutableAttributedString(
        string: alert.message!,
        attributes: [NSFontAttributeName:UIFont.systemFontOfSize(13)])
    alert.setValue(messageAttributed, forKey: "attributedMessage")


    // set the buttons to non-blue, if we have buttons
    if let buttonColor = buttonColor {
        alert.view.tintColor = buttonColor
    }
}

func setSubviewLabelsToTextColor(textColor: UIColor, view:UIView) {
    for subview in view.subviews {
        if let label = subview as? UILabel {
            label.textColor = textColor
        } else {
            setSubviewLabelsToTextColor(textColor, view: subview)
        }
    }
}

This works in some situations perfectly, and in others it's a total fail (the tint colors do not show as expected).

Mert answered 6/4, 2016 at 2:37 Comment(0)
D
3

There is a problem with setting the tint color on the view after presenting; even if you do it in the completion block of presentViewController:animated:completion:, it causes a flicker effect on the color of the button titles. This is sloppy, unprofessional and completely unacceptable.

Other solutions presented depend on the view hierarchy remaining static, something that Apple is loathe to do. Expect those solutions to fail in future releases of iOS.

The one sure-fire way to solve this problem and to do it everywhere, is via adding a category to UIAlertController and swizzling the viewWillAppear.

The header:

//
//  UIAlertController+iOS9TintFix.h
//
//  Created by Flor, Daniel J on 11/2/15.
//

#import <UIKit/UIKit.h>

@interface UIAlertController (iOS9TintFix)

+ (void)tintFix;

- (void)swizzledViewWillAppear:(BOOL)animated;

@end

The implementation:

//
//  UIAlertController+iOS9TintFix.m
//
//  Created by Flor, Daniel J on 11/2/15.
//

#import "UIAlertController+iOS9TintFix.h"
#import <objc/runtime.h>

@implementation UIAlertController (iOS9TintFix)

+ (void)tintFix {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method method  = class_getInstanceMethod(self, @selector(viewWillAppear:));
        Method swizzle = class_getInstanceMethod(self, @selector(swizzledViewWillAppear:));
        method_exchangeImplementations(method, swizzle);});
}

- (void)swizzledViewWillAppear:(BOOL)animated {
    [self swizzledViewWillAppear:animated];
    for (UIView *view in self.view.subviews) {
        if (view.tintColor == self.view.tintColor) {
            //only do those that match the main view, so we don't strip the red-tint from destructive buttons.
            self.view.tintColor = [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0];
            [view setNeedsDisplay];
        }
    }
}

@end

Add a .pch (precompiled header) to your project and include the category:

#import "UIAlertController+iOS9TintFix.h"

Make sure you register your pch in the project properly, and it will include the category methods in every class that uses the UIAlertController.

Then, in your app delegates didFinishLaunchingWithOptions method, import your category and call

[UIAlertController tintFix];

and it will automatically propagate to every single instance of UIAlertController within your app, whether launched by your code or anyone else's.

This solution works for both iOS 8.X and iOS 9.X and lacks the flicker of the tint change post-presentation approach. It is also completely agnostic with respect to the view hierarchy of the sub-views of the UIAlertController.

Happy hacking!

Depurate answered 3/11, 2015 at 2:35 Comment(8)
This solution works, mostly. On device rotate, however, the tints go back to the way they were, before the swizzling.Edric
Dhiraj, I just tested this again in a project setup explicitly to explore your findings, and I do not concur. The tint does not go back to the way it was on rotate.Depurate
Verified functional on xcode 6.4, and xcode 7.0. Running simulators of all variations of 8.X and 9.0. If requested, I will put the project up on github.Depurate
Well you could go ahead and put up a project, but this is what I was seeing happening to me. It was also not working on iPad. Based on your method swizzling idea, however, I was able to make it work by swizzling viewDidLayoutSubviews, though.Edric
If you put up a project, then I could submit a pull request with the viewDidLayoutSubviews swizzle, which is what I've just used and submitted in the latest build of my app to the App Store and you can have a look, maybe?Edric
Sure, sorry I've been offline for a spell, but let me get one pushed up there for you.Depurate
This is the test project I wrote to isolate the swizzle from all other aspects of the codebase: github.com/DJFlor/UIAlertControllerTestDepurate
Works great, even on rotation, when swizzling viewDidLayoutSubviews.Metaxylem
G
3

Please find this category. I am able to change FONT and Color of UIAlertAction and UIAlertController.

Use:

UILabel * appearanceLabel = [UILabel appearanceWhenContainedIn:UIAlertController.class, nil];
[appearanceLabel setAppearanceFont:yourDesireFont]];  
Gilson answered 27/5, 2016 at 10:26 Comment(1)
Please, paste the code here or use a service that does not require people to log in.Nath
G
2

Solution/Hack for iOS9

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Test Error" message:@"This is a test" preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        NSLog(@"Alert View Displayed");
 [[[[UIApplication sharedApplication] delegate] window] setTintColor:[UIColor whiteColor]];
    }];

    [alertController addAction:cancelAction];
    [[[[UIApplication sharedApplication] delegate] window] setTintColor:[UIColor blackColor]];
    [self presentViewController:alertController animated:YES completion:^{
        NSLog(@"View Controller Displayed");
    }];
Geof answered 23/9, 2015 at 18:50 Comment(2)
I tried this. Note that you're reverting the window tint setting once the alert controller is presented. I see the color switching back right on the alert controller. I believe the revertion must be done once any action is tapped.Electrokinetic
Thanks @Germán for pointing that out.. Made the changes to the code. I am handling the revert in the AlertAction as of now.. But yes I agree that can be handled in the dimiss handler tooGeof
P
2

For iOS 9.0 and above use this code in app delegate

[[UIView appearanceWhenContainedInInstancesOfClasses:@[[UIAlertController class]]] setTintColor:[UIColor redColor]];
Patentor answered 12/4, 2018 at 10:8 Comment(0)
T
2

Swift 5.0

let titleAttrString = NSMutableAttributedString(string: "This is a title", attributes: [NSAttributedString.Key.font: UIFont(name: "CustomFontName", size: 17) as Any])
let messageAttrString = NSMutableAttributedString(string: "This is a message", attributes: [NSAttributedString.Key.font: UIFont(name: "CustomFontName", size: 13) as Any])

alertController.setValue(titleAttrString, forKey: "attributedTitle")
alertController.setValue(messageAttrString, forKey: "attributedMessage")
Tybalt answered 3/1, 2020 at 5:51 Comment(0)
P
1

I work for Urban Outfitters. We have an open source pod, URBNAlert, that we used in all of our apps. It's based off of UIAlertController, but is highly customizable.

Source is here: https://github.com/urbn/URBNAlert

Or simply install by the pod by placing URBNAlert in your Podfile

Heres some sample code:

URBNAlertViewController *uac = [[URBNAlertViewController alloc] initWithTitle:@"The Title of my message can be up to 2 lines long. It wraps and centers." message:@"And the message that is a bunch of text. And the message that is a bunch of text. And the message that is a bunch of text."];

// You can customize style elements per alert as well. These will override the global style just for this alert.
uac.alertStyler.blurTintColor = [[UIColor orangeColor] colorWithAlphaComponent:0.4];
uac.alertStyler.backgroundColor = [UIColor orangeColor];
uac.alertStyler.textFieldEdgeInsets = UIEdgeInsetsMake(0.0, 15.0, 0.0, 15.0);
uac.alertStyler.titleColor = [UIColor purpleColor];
uac.alertStyler.titleFont = [UIFont fontWithName:@"Chalkduster" size:30];
uac.alertStyler.messageColor = [UIColor blackColor];
uac.alertStyler.alertMinWidth = @150;
uac.alertStyler.alertMaxWidth = @200;
// many more styling options available 

[uac addAction:[URBNAlertAction actionWithTitle:@"Ok" actionType:URBNAlertActionTypeNormal actionCompleted:^(URBNAlertAction *action) {
      // Do something
}]];

[uac addAction:[URBNAlertAction actionWithTitle:@"Cancel" actionType:URBNAlertActionTypeCancel actionCompleted:^(URBNAlertAction *action) {
      // Do something
}]];

[uac show];
Peirce answered 25/10, 2015 at 15:48 Comment(2)
Does this support the ActionSheet style?Contiguous
@Contiguous it does not, it is is purely just for Alerts.. That being said.. if its something you desire create an issue on the repo. That is something we have discussed adding support for beforePeirce
J
1

To change the color of one button like CANCEL to the red color you can use this style property called UIAlertActionStyle.destructive :

let prompt = UIAlertController.init(title: "Reset Password", message: "Enter Your E-mail :", preferredStyle: .alert)
        let okAction = UIAlertAction.init(title: "Submit", style: .default) { (action) in
              //your code
}

let cancelAction = UIAlertAction.init(title: "Cancel", style: UIAlertActionStyle.destructive) { (action) in
                //your code
        }
        prompt.addTextField(configurationHandler: nil)
        prompt.addAction(okAction)
        prompt.addAction(cancelAction)
        present(prompt, animated: true, completion: nil);
Josephinejosephson answered 18/1, 2017 at 10:55 Comment(0)
M
0

A bit clunky, but this works for me right now to set background and text colors. I found it here.

UIView * firstView = alertController.view.subviews.firstObject;
    UIView * nextView = firstView.subviews.firstObject;
    nextView.backgroundColor = [UIColor blackColor];
Metastasis answered 17/5, 2015 at 4:5 Comment(1)
It does work for the background color but it never changes the tint color this is what I am a bit confused aboutGeof
R
0

I have created one method objective-C

-(void)customAlertTitle:(NSString*)title message:(NSString*)message{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:nil delegate:nil cancelButtonTitle:@"NO" otherButtonTitles:@"YES", nil];
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 80)];

UILabel *titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 270, 50)];
titleLabel.text = title;
titleLabel.font = [UIFont boldSystemFontOfSize:20];
titleLabel.numberOfLines = 2;
titleLabel.textColor = [UIColor redColor];
titleLabel.textAlignment = NSTextAlignmentCenter;

[subView addSubview:titleLabel];

UILabel *messageLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 30, 270, 50)];
messageLabel.text = message;
messageLabel.font = [UIFont systemFontOfSize:18];
messageLabel.numberOfLines = 2;
messageLabel.textColor = [UIColor redColor];
messageLabel.textAlignment = NSTextAlignmentCenter;

[subView addSubview:messageLabel];

[alertView setValue:subView forKey:@"accessoryView"];
[alertView show];
}

Code wokring perfectly on Xcode 8.3.1. You can customise according to requirement.

Rabelais answered 27/4, 2017 at 7:35 Comment(0)
A
0

I just use this kind of demand, seemingly and system, details are slightly different, so we are ... OC realized Alert and Sheet popup window encapsulation.

Often encountered in daily development need to add a figure to Alert or change a button color, such as "simple" demand, today brings a and system components of highly similar and can fully meet the demand of customized packaging components.

Github:https://github.com/ReverseScale/RSCustomAlertView

Agrobiology answered 5/1, 2018 at 5:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.