43

Is there a way to change the alignment of the message displayed inside a UIAlertController on iOS 8?

I believe accessing the subviews and changing it for the UILabel is not possible anymore.

dkaisers
  • 824
  • 1
  • 8
  • 15

8 Answers8

76

I have successfully used the following, for both aligning and styling the text of UIAlertControllers:

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.Left

let messageText = NSMutableAttributedString(
    string: "The message you want to display",
    attributes: [
        NSParagraphStyleAttributeName: paragraphStyle,
        NSFontAttributeName : UIFont.preferredFontForTextStyle(UIFontTextStyleBody),
        NSForegroundColorAttributeName : UIColor.blackColor()
    ]
)

myAlert.setValue(messageText, forKey: "attributedMessage")

You can do a similar thing with the title, if you use "attributedTitle", instead of "attributedMessage"

Swift 3 update

The above still works in Swift 3, but the code has to be slightly altered to this:

let messageText = NSMutableAttributedString(
    string: "The message you want to display",
    attributes: [
        NSParagraphStyleAttributeName: paragraphStyle,
        NSFontAttributeName : UIFont.preferredFont(forTextStyle: UIFontTextStyle.body),
        NSForegroundColorAttributeName : UIColor.black
    ]
)

myAlert.setValue(messageText, forKey: "attributedMessage")

Swift 4 update

let messageText = NSMutableAttributedString(
    string: "The message you want to display",
    attributes: [
        NSAttributedStringKey.paragraphStyle: paragraphStyle,
        NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body),
        NSAttributedStringKey.foregroundColor: UIColor.black
    ]
)

myAlert.setValue(messageText, forKey: "attributedMessage")

Swift 5 update

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = alignment
let messageText = NSAttributedString(
    string: "message",
    attributes: [
        NSAttributedString.Key.paragraphStyle: paragraphStyle,
        NSAttributedString.Key.foregroundColor : UIColor.primaryText,
        NSAttributedString.Key.font : UIFont(name: "name", size: size)
    ]
)

myAlert.setValue(messageText, forKey: "attributedMessage")
eharo2
  • 2,553
  • 1
  • 29
  • 39
Eduardo
  • 8,362
  • 6
  • 38
  • 72
  • 2
    Seems like this is private API use, did this make it into the App Store? – powerj1984 Jul 06 '15 at 14:10
  • 1
    @powerj1984 yes, it did. – Eduardo Jul 06 '15 at 15:02
  • 1
    What's private about it? – Lucas van Dongen Oct 29 '16 at 18:21
  • 1
    Is there any objective-c version? – Sonic Master May 24 '17 at 03:17
  • 1
    @SonicMaster sorry, but I don't have experience with Objective-C. I guess, since this is mainly assignments and calling functions, the translation should be straightforward. – Eduardo May 24 '17 at 05:16
  • I tried to see if this method works for changing text alignment when using `UIAlertAction` items in `UIAlertController` as well, but it resulted in some key-value compliance and undefined key exceptions and the controller not displaying. – somedev Jan 22 '18 at 07:47
  • Update for Swift 4 let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = NSTextAlignment.justified let messageText = NSMutableAttributedString( string: alertMsg, attributes: [ NSAttributedStringKey.paragraphStyle: paragraphStyle, NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: UIFontTextStyle.body), NSAttributedStringKey.foregroundColor : UIColor.black ] ) – Naveen Kumawat Mar 24 '18 at 04:54
  • Is there any documentation for keys like "attributedMessage" and "attributedTitle"? How will I get a list of all available keys? – Akhil Shrivastav Aug 12 '18 at 15:04
  • @AkhilShrivastav google "UIAlertAction runtime headers", there are tons of undocumented keys that can be used to customize native components – jjjjjjjj Jan 17 '19 at 04:29
10

Use the below code

UIAlertController * alert = [UIAlertController
                                 alertControllerWithTitle:[title lowercaseString]
                                 message:[message lowercaseString]
                                 preferredStyle:UIAlertControllerStyleAlert];

    if (alertStyle == kUIAlertStylePlainText)
    {
        [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {

        }];
    }

    if (okTitle) {
        UIAlertAction* ok = [UIAlertAction actionWithTitle:[okTitle lowercaseString] style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action) {
                                                       callback(alert, action, nil);
                                                   }];
        [alert addAction:ok];
    }

    if (cancelTitle) {
        UIAlertAction* cancel = [UIAlertAction actionWithTitle:[cancelTitle lowercaseString] style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * action) {
                                                           callback(alert, nil, action);
                                                       }];
        [alert addAction:cancel];
    }


    NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init];
    paraStyle.alignment = NSTextAlignmentLeft;

    NSMutableAttributedString *atrStr = [[NSMutableAttributedString alloc] initWithString:[message lowercaseString] attributes:@{NSParagraphStyleAttributeName:paraStyle,NSFontAttributeName:[UIFont systemFontOfSize:13.0]}];

    [alert setValue:atrStr forKey:@"attributedMessage"];
    [viewInstance presentViewController:alert animated:YES completion:nil];
Ganesh Bavaskar
  • 754
  • 6
  • 15
10

I took up @Amos's answer and made it into a convenient extension:

public extension UIAlertController {

    func setMessageAlignment(_ alignment : NSTextAlignment) {
        let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
        paragraphStyle.alignment = alignment

        let messageText = NSMutableAttributedString(
            string: self.message ?? "",
            attributes: [
                NSAttributedString.Key.paragraphStyle: paragraphStyle,
                NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12),
                NSAttributedString.Key.foregroundColor: UIColor.gray
            ]
        )

        self.setValue(messageText, forKey: "attributedMessage")
    }
}

Then you can simply set the alignment value: myAlert.setMessageAlignment(.left)

Ariel Steiner
  • 368
  • 3
  • 9
6

Navigate to subview tree until you get to the UILabels for the title and the message

NSArray *viewArray = [[[[[[[[[[[[alertController view] subviews] firstObject] subviews] firstObject] subviews] firstObject] subviews] firstObject] subviews] firstObject] subviews];
UILabel *alertTitle = viewArray[0]
UILabel *alertMessage = viewArray[1];
alertMessage.textAlignment = NSTextAlignmentLeft;

However, you may want to make an category for it

@interface UIAlertController (ShowMeTheLabels)

@property (nonatomic, strong) UILabel *titleLabel, *messageLabel;

@end

@implementation UIAlertController (ShowMeTheLabels)
@dynamic titleLabel;
@dynamic messageLabel;

- (NSArray *)viewArray:(UIView *)root {
    NSLog(@"%@", root.subviews);
    static NSArray *_subviews = nil;
    _subviews = nil;
    for (UIView *v in root.subviews) {
        if (_subviews) {
            break;
        }
        if ([v isKindOfClass:[UILabel class]]) {
            _subviews = root.subviews;
            return _subviews;
        }
        [self viewArray:v];
    }
    return _subviews;
}

- (UILabel *)titleLabel {
    return [self viewArray:self.view][0];
}

- (UILabel *)messageLabel {
    return [self viewArray:self.view][1];
}

@end

Then you can align the text like this

yourAlertController.messageLabel.textAlignment = NSTextAlignmentLeft;
DerrickHo328
  • 4,664
  • 7
  • 29
  • 50
  • 22
    `NSArray *viewArray = [[[[[[[[[[[[alertController view] subviews] firstObject] subviews] firstObject] subviews] firstObject] subviews] firstObject] subviews] firstObject] subviews];` That takes the cake for most nested ObjC I've never seen o.0 – Chris Wagner Aug 01 '15 at 00:38
  • 6
    Yes. Apple doesn't really want people to mess with it. It's is a far better investment to make a custom pop up alert than to tinker with something so deeply nested. – DerrickHo328 Aug 01 '15 at 00:49
  • 2
    They never did come through with their promise, in one of the 2013 sessions they mentioned that they added a UIView property so that we could put whatever we want in there... It never made it in. – Chris Wagner Aug 02 '15 at 22:56
  • Actually this is the correct modern answer for the current API I guess! It works like a charm! Sweet! Thanks man! – Randika Vishman Feb 25 '16 at 19:15
  • Has someone make it to the app store? – Sonic Master Mar 14 '17 at 12:51
  • It crashes on iOS 11 (tested on real device): 'NSInvalidArgumentException', reason: '-[UIView setTextAlignment:]: unrecognized selector sent to instance... – Ariel Malka Apr 15 '19 at 11:55
3

Swift 4.2 + multiline string linebreak indentation

let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle

paragraphStyle.headIndent = 14

let messageText = NSMutableAttributedString(
    string: "... multiline string need linebreak indentation ...",
    attributes: [
        NSAttributedString.Key.paragraphStyle: paragraphStyle,
        NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12),
        NSAttributedString.Key.foregroundColor: UIColor.gray
    ]
)

alert.setValue(messageText, forKey: "attributedMessage")
Amos
  • 2,222
  • 1
  • 26
  • 42
2

The following method will set the text alignment, while preserving the default font size.

static void makeAlertControllerLeftAligned( UIAlertController* avc )
{
    NSMutableParagraphStyle *paraStyle = [[[NSMutableParagraphStyle alloc] init] autorelease];
    paraStyle.alignment = NSTextAlignmentLeft;
    NSMutableAttributedString *atrStr =
        [[[NSMutableAttributedString alloc] initWithString:avc.message attributes:@{
             NSParagraphStyleAttributeName:paraStyle,
             NSFontAttributeName: [UIFont preferredFontForTextStyle: UIFontTextStyleFootnote],
         }]
         autorelease];
    [avc setValue:atrStr forKey:@"attributedMessage"];
}
zeroimpl
  • 2,746
  • 22
  • 19
0

This property exposes the text fields, so could probably be used to configure them:

textFields

The array of text fields displayed by the alert. (read-only)

Declaration

SWIFT

var textFields: [AnyObject]? { get }

OBJECTIVE-C

@property(nonatomic, readonly) NSArray *textFields

Discussion

Use this property to access the text fields displayed by the alert. The text fields are in the order in which you added them to the alert controller. This order also corresponds to the order in which they are displayed in the alert.

Note: even though it says the property is readonly, it returns an array of text field object references which can be used to modify the controls.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • 1
    Aren't those just the UITextFields that you can add to the UIAlertController? I only display a text through the message property that is styled as a bullet list and thus would benefit from being left aligned. – dkaisers Sep 21 '14 at 18:44
  • 2
    @DominikKaisers Yeah you are right; perhaps you can use the text fields and not use the message property? – trojanfoe Sep 21 '14 at 18:45
  • 1
    Yeah, that probably would be a workaround. I'll give it a try, if nobody has an easier way. – dkaisers Sep 21 '14 at 18:46
  • 4
    These are the text input fields, not the message. – Bjarte Jan 21 '16 at 09:06
-1
yourAlertController.messageLabel.textAlignment = NSTextAlignmentLeft;
4b0
  • 21,981
  • 30
  • 95
  • 142
Nagabhushan Vaddi
  • 119
  • 1
  • 1
  • 8