How to set height and width of a UIAlertController in IOS 8

24,578

Solution 1

I do not think you can set the size. Bad workaround is, to set \n on the message. UIAlertView also has same limitation.

I will suggest to use UIPopoverController and implement your own dismiss button, since UIAlertController's purpose is more to display alert messages to the user (short message) per Apple Documentation. I do not think wall of message can be considered as alert message.

Generally, I think this limitation is set by Apple as a reminder this view is to display short message to users as part of their UX.

Edited with sample code First, sorry, I mean UIPopoverPresentViewController, not UIPopoverController

Here is the sample class:

@interface DemoPopOverPresentViewController : UIViewController

- (instancetype)initWithTitle:(NSString*)title message:(NSString*)message buttonTitle:(NSString*)buttonTitle;

@property NSString* titleText;
@property NSString* messageText;
@property NSString* buttonTitleText;

@property UILabel* titleLabel;
@property UILabel* textLabel;
@property UIButton* submitButton;

@end

@implementation DemoPopOverPresentViewController

- (instancetype)initWithTitle:(NSString*)title message:(NSString*)message buttonTitle:(NSString*)buttonTitle;
{
    self = [super init];

    if ( self ) {
        _titleText = title;
        _messageText = message;
        _buttonTitleText = buttonTitle;
    }

    return self;
}

- (void)viewDidLoad;
{
    [super viewDidLoad];

    _titleLabel = [UILabel new];
    [_titleLabel setTextAlignment:NSTextAlignmentCenter];
    [_titleLabel setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]];
    [_titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
    [_titleLabel setText:_titleText];
    [self.view addSubview:_titleLabel];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_titleLabel]|"     options:0 metrics:nil views:NSDictionaryOfVariableBindings(_titleLabel)]];

    _textLabel = [UILabel new];
    [_textLabel setTextAlignment:NSTextAlignmentCenter];
    [_textLabel setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]];
    [_textLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
    [_textLabel setNumberOfLines:0];
    [_textLabel setText:_messageText];
    [self.view addSubview:_textLabel];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_textLabel]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_textLabel)]];

    _submitButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [_submitButton setTitle:_buttonTitleText forState:UIControlStateNormal];
    [_submitButton addTarget:self action:@selector(submitButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
    [_submitButton setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:_submitButton];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_submitButton]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_submitButton)]];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_titleLabel(<=44.0)]-16-[_textLabel]-16-[_submitButton(<=44.0)]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_titleLabel,_textLabel,_submitButton)]];
}

- (void)submitButtonTouched:(id)sender;
{
    [self dismissViewControllerAnimated:YES completion:^{

    }];
}

@end

Then on presentingViewController,

  • first, it will need to implement UIPopoverPresentationControllerDelegate delegate
  • then to initialise the class:

    DemoPopOverPresentViewController* controller = [[DemoPopOverPresentViewController alloc] initWithTitle:@"Info" message:@"The quick brown fox jumps over the lazy dog" buttonTitle:@"Dismiss"];
    controller.modalPresentationStyle = UIModalPresentationPopover;
    // set the content size of your 'alert view'
    controller.preferredContentSize = CGSizeMake(200.0, 150.0);
    UIPopoverPresentationController* pc = [controller popoverPresentationController];
    pc.sourceView = self.view;
    pc.delegate = self;
    pc.sourceRect = CGRectMake(self.view.frame.size.width/2.0, self.view.frame.size.height/2.0, 0.0, 0.0);
    pc.permittedArrowDirections = NULL;
    [self presentViewController:controller animated:YES completion:^{
    
    }];
    
  • implement delegate method for UIPopoverPresentationControllerDelegate: - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller and return UIModalPresentationNone

Solution 2

You can control UIAlertController via constraints.

Lets say we want this alert to be wider:

Alert with big content

If you take a look at view hierarchy, you'll see that UIKit restricts UIAlertController width to 270:

View hierarchy

Checking this view children, you can find that its first child also has this constraint with priority 998.

Knowing that we can update this constraints before we present alert controller. Something like this:

    let alert = UIAlertController(title: "Some gorgeous very big big big title with many words", message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam a augue eget magna maximus posuere. Donec pellentesque lacus ut tellus mollis, eget congue nulla dapibus. Sed pharetra porta lorem, ac faucibus risus scelerisque vitae. Aenean lacinia lobortis quam quis finibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed odio nisl, pretium a turpis in, pulvinar bibendum augue. Proin id ligula elementum, pulvinar lorem et, suscipit turpis. Duis in tortor arcu. Donec in dapibus ex.\n\nDuis sit amet lacus nec mauris blandit dignissim. Sed efficitur vestibulum sapien ut condimentum. Donec a lorem sit amet augue imperdiet dictum sed eu sapien. Donec in congue quam, vitae luctus augue. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vivamus felis ipsum, malesuada eu dictum non, imperdiet ut urna. Vivamus tempus ante sit amet quam interdum feugiat. Ut at nulla nibh.", preferredStyle: .alert)

    alert.addAction(UIAlertAction(title: "Hide this", style: .default, handler: nil))
    // Filtering width constraints of alert base view width
    let widthConstraints = alert.view.constraints.filter({ return $0.firstAttribute == .width })
    alert.view.removeConstraints(widthConstraints)
    // Here you can enter any width that you want
    let newWidth = UIScreen.main.bounds.width * 0.90
    // Adding constraint for alert base view
    let widthConstraint = NSLayoutConstraint(item: alert.view,
                                             attribute: .width,
                                             relatedBy: .equal,
                                             toItem: nil,
                                             attribute: .notAnAttribute,
                                             multiplier: 1,
                                             constant: newWidth)
    alert.view.addConstraint(widthConstraint)
    let firstContainer = alert.view.subviews[0]
    // Finding first child width constraint
    let constraint = firstContainer.constraints.filter({ return $0.firstAttribute == .width && $0.secondItem == nil })
    firstContainer.removeConstraints(constraint)
    // And replacing with new constraint equal to alert.view width constraint that we setup earlier
    alert.view.addConstraint(NSLayoutConstraint(item: firstContainer,
                                                attribute: .width,
                                                relatedBy: .equal,
                                                toItem: alert.view,
                                                attribute: .width,
                                                multiplier: 1.0,
                                                constant: 0))
    // Same for the second child with width constraint with 998 priority
    let innerBackground = firstContainer.subviews[0]
    let innerConstraints = innerBackground.constraints.filter({ return $0.firstAttribute == .width && $0.secondItem == nil })
    innerBackground.removeConstraints(innerConstraints)
    firstContainer.addConstraint(NSLayoutConstraint(item: innerBackground,
                                                    attribute: .width,
                                                    relatedBy: .equal,
                                                    toItem: firstContainer,
                                                    attribute: .width,
                                                    multiplier: 1.0,
                                                    constant: 0))

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

Now your alert will take 90% of your screen:

90% wide screen alert

Right now I find only this solution. There may be more elegant variant and secure solution, but I think you get the idea.

Solution 3

I know this is closed but I found you can add constraints to the alertviewcotnroller.view like this

var height:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.view.frame.height * 0.80)
    alertController.view.addConstraint(height);

Solution 4

This should certainly help you. (Swift 4.2)

let alert = UIAlertController(title: "Alert", message: "Some message", preferredStyle: .actionSheet)

alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) in

}))
alert.addAction(UIAlertAction(title: "Some", style: .default))
alert.addAction(UIAlertAction(title: "Some", style: .default))

let height:NSLayoutConstraint = NSLayoutConstraint(item: alert.view, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: view.frame.height)
alert.view.addConstraint(height);
present(alert, animated: true)

Solution 5

Just update width constraint value

// calculate new width
let newWidth = UIScreen.main.bounds.width * 0.90 - 270

// update width constraint value for main view
if let viewWidthConstraint = alertController.view.constraints.filter({ return $0.firstAttribute == .width }).first{
    viewWidthConstraint.constant = newWidth
}

// update width constraint value for container view
if let containerViewWidthConstraint = alertController.view.subviews.first?.constraints.filter({ return $0.firstAttribute == .width }).first {
    containerViewWidthConstraint.constant = newWidth
}

//present alertController
self.present(alertController, animated: true, completion: nil)
Share:
24,578
SGDev
Author by

SGDev

Updated on March 01, 2021

Comments

  • SGDev
    SGDev about 3 years

    I have a UIAlertController with an TextFile. The problem is that the default UIAlertController is a very small size. It's text cannot be seen properly.

    So, I want to increase the height and width of the UIAlertController. In other words, I want to create a custom UIAlertController. What would be the way to do that?

  • SGDev
    SGDev over 9 years
    Yes, i know this is a good approach to show a UIPopoverController for a long message but client wants UIAlertController.
  • Peter
    Peter over 9 years
    Then, you can use UIPopOverController to mimic the UI of alert window.
  • SGDev
    SGDev over 9 years
    can you give me a sample code for it or any tutorial that help me?
  • Chucky
    Chucky almost 8 years
    The problem with Popover from what I can tell is that it has to point to where it came from, unlike an alert which just appears on the screen.
  • Chucky
    Chucky almost 8 years
    I too have only been able to get this to work for height.
  • Lloyd Sargent
    Lloyd Sargent almost 8 years
    Works only for iPhone. iPad barfs with “Unable to simultaneously satisfy constraints.” As such, if Apple adds constraints to iPhone, then the same problem will occur.
  • Bhavin Trivedi
    Bhavin Trivedi over 7 years
    @Jonathan Ellis that same way you can add constraint for width as below : ** var width:NSLayoutConstraint = NSLayoutConstraint(item: alertController.view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.view.frame.width * 0.80) alertController.view.addConstraint(width); ** In my project i used this for width control and it worked..
  • Sangram Shivankar
    Sangram Shivankar over 6 years
    how to set width of alertviewcontroller
  • Cynichniy Bandera
    Cynichniy Bandera over 4 years
    Clever idea, but unfortunately, is not working for me. Perhaps the hierarchy of uialertcontroller view changed in ios13.