64

I have seen a couple screen shots of a UIAlertControllers with an image on the left of the row but I do not seen it in the documentation. An example visual is http://imgur.com/SISBvjB Here is the code that I have for my controller right now:

UIAlertController * view =   [UIAlertController
                                 alertControllerWithTitle:@"My Title"
                                 message:@"Select you Choice"
                                 preferredStyle:UIAlertControllerStyleActionSheet];
    UIAlertAction* ok = [UIAlertAction
                         actionWithTitle:@"OK"
                         style:UIAlertActionStyleDefault
                         handler:^(UIAlertAction * action)
                         {
                          }];
    [view addAction:ok];
    [self presentViewController:view animated:YES completion:nil];
RajeshKumar R
  • 15,445
  • 2
  • 38
  • 70
user1079052
  • 3,803
  • 4
  • 30
  • 55
  • 1
    There is no API to customize the buttons of a `UIAlertController`. Whatever screenshots you have seen are not using `UIAlertController`. – rmaddy Oct 13 '14 at 19:11
  • Maybe I misunderstood the OP but I don't think he wants to customize the alert buttons but add an image to the alert. – PruitIgoe Oct 13 '14 at 19:30
  • This is what I am trying to create http://imgur.com/SISBvjB – user1079052 Oct 14 '14 at 12:56
  • 1
    @user1079052 you should accept JPs answer as the correct answer. It is definetly the best one on SO – soulshined Dec 27 '14 at 08:16

8 Answers8

123

And that's how it's done:

let image = UIImage(named: "myImage")
var action = UIAlertAction(title: "title", style: .default, handler: nil)
action.setValue(image, forKey: "image")
alert.addAction(action)

the image property is not exposed, so there's no guarantee of this working in future releases, but works fine as of now

Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
JP Hribovsek
  • 6,707
  • 2
  • 21
  • 26
  • 4
    Thank you! Here is the objective C equivalent: UIImage *image = [UIImage imageNamed:@"image.png"]; [bluetoothButton setValue:image forKey:@"image"]; – user1079052 Oct 15 '14 at 13:40
  • Do you happen to know what is the key to set an image on the right side, essentially the accessory view? – user1079052 Oct 15 '14 at 14:23
  • There doesn't seem to be a property for that. You would have to build a more hacky solution that recursively loops through all the alertController's view subviews, and then add an image subview to that. Again, could you mark my answer as correct if that worked for you – JP Hribovsek Oct 15 '14 at 15:17
  • 2
    Thank you @JPHribovsek poor SO user. This answer should be accepted as the correct answer. All i can do is upvote – soulshined Dec 27 '14 at 08:15
  • I tried it in Objective-c..it works but the image gets displayed on the left side. Any way of putting it in the middle of the button? – Claus Jan 14 '15 at 16:14
  • 9
    Apple won't reject it? – Georg May 27 '15 at 11:35
  • @Georg no, I don't see why – JP Hribovsek May 27 '15 at 17:37
  • 2
    doesn't seem to work with xCode 6.3 - only blue squares in places of the icons – hris.to Jun 11 '15 at 14:52
  • 1
    but the image tintcolor is changed, how can i set original image to it? – Patel Jigar Oct 08 '15 at 09:14
  • 6
    @PatelJigar change rendering mode to always original `action.setValue(image.imageWithRenderingMode(.AlwaysOriginal), forKey: "image")` – jaytrixz Dec 29 '15 at 10:46
  • How can you give forKey:@"image"? Is it inbuild? I changed the key but it crashed. – user3182143 Jan 21 '16 at 09:25
  • works on iPhone, but on iPad if I set alertcontroller.view.tintcolor and add the image, the tintcolor is ignored. – masgar Mar 21 '16 at 11:02
  • 1
    @masgar see the comments above for Patel Jigar, @jaytrixz mentions `imageWithRenderingMode(.AlwaysOriginal)` – Efren May 26 '17 at 03:12
  • the " forKey:'image' "... where do you even find documentation on this? – Ryan Pierce Jul 23 '17 at 15:01
  • Only seeing a solid blue rectangle? This fix will help. `action.setValue(UIImage(named:"image")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), forKey: "image")` It's a shame Apple didn't provide a simple method to add in images, BUT... hate to rain on the parade, this method here would seem to really be non compliant with the guidelines. It essentially places an image into the alert view's button area and affects the sizing of other alertview buttons. Plus, is this accessibility compliant? These are just two considerations. – user4806509 Aug 05 '17 at 21:52
  • 1
    @JPHribovsek because this is using a non public api of an apple framework. that is pretty much a guarantee to get rejected – David Seek Jul 22 '18 at 03:27
  • @DavidSeek nope, the API used here is `setValue:forKey:`, which is a public API; been used in the app store many times, no rejects – JP Hribovsek Jan 24 '19 at 22:20
27
UIAlertController * view=   [UIAlertController
                             alertControllerWithTitle:@"Staus ! "
                             message:@"Select your current status"
                             preferredStyle:UIAlertControllerStyleActionSheet];


UIAlertAction* online = [UIAlertAction
                     actionWithTitle:@"Online"
                     style:UIAlertActionStyleDefault
                     handler:^(UIAlertAction * action)
                     {
                         //Do some thing here
                         [view dismissViewControllerAnimated:YES completion:nil];

                     }];
UIAlertAction* offline = [UIAlertAction
                         actionWithTitle:@"Offline"
                         style:UIAlertActionStyleDefault
                         handler:^(UIAlertAction * action)
                         {
                             [view dismissViewControllerAnimated:YES completion:nil];

                         }];
UIAlertAction* doNotDistrbe = [UIAlertAction
                         actionWithTitle:@"Do not disturb"
                         style:UIAlertActionStyleDefault
                         handler:^(UIAlertAction * action)
                         {
                             [view dismissViewControllerAnimated:YES completion:nil];

                         }];
UIAlertAction* away = [UIAlertAction
                               actionWithTitle:@"Do not disturb"
                               style:UIAlertActionStyleDestructive
                               handler:^(UIAlertAction * action)
                               {
                                   [view dismissViewControllerAnimated:YES completion:nil];

                               }];

[online setValue:[[UIImage imageNamed:@"online.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"];
[offline setValue:[[UIImage imageNamed:@"offline.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"];
[doNotDistrbe setValue:[[UIImage imageNamed:@"DND.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"];
[away setValue:[[UIImage imageNamed:@"away.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"];





[view addAction:online];
[view addAction:away];
[view addAction:offline];
[view addAction:doNotDistrbe];
[self presentViewController:view animated:YES completion:nil];
Pang
  • 9,564
  • 146
  • 81
  • 122
dheerendra
  • 537
  • 6
  • 8
  • Hi,How could we add the image to left of the text. I have that requirement in my app.Thank You – SMS Oct 15 '15 at 12:58
  • @SMS Until Apple expose this as a public property it may not be as simple as "wanting to move the image". You could try subclassing UIAlertController and override the `viewWillLayoutSubviews` and access the object via KVO like above `let image = self.valueForKey("image")` but that would give you the image. Long story short, it is probably very difficult to do it in such a way that apple won't reject your app. Easiest option is to create your own Alert Controller – Tim Jan 27 '16 at 23:48
  • That works to add an image on the button (action) of the view. Not work to add image to message. – doxsi Jul 06 '16 at 12:01
  • It's just what I needed. The only problem is that you use the image you use, although it has a lot of resolution, it always looks blurred in the menu. Does anyone else have this problem? – Kepa Santos Feb 22 '17 at 16:26
13

You could add an image above the title label by subclassing UIAlertController and adding \n to the title string to make space for the UIImageView. You'd have to compute the layout based on the font size. For images in the UIAlertAction use KVC like so self.setValue(image, forKey: "image"). I would recommend to use an extension that checks for responds(to:). Here is sample implementation.

enter image description here

jtth
  • 876
  • 1
  • 12
  • 40
stringCode
  • 2,274
  • 1
  • 23
  • 32
  • Awesome, mate. Thanks for the solution. – Hexfire Jan 16 '18 at 11:24
  • This solution code does not make space for UIImageView above title string. See - [Inline Code Link](https://pastebin.com/QdcVkRZM), [Inline Image Link](https://ibb.co/ZY3LCtx). – jtth Jan 31 '19 at 20:17
11

For swift

let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let action = UIAlertAction(title: NSLocalizedString("Share", comment: ""), style: .default, handler: { _ in
        })
let image = UIImage(named: "Temp1")
action.setValue(image?.withRenderingMode(.alwaysOriginal), forKey: "image")
actionSheet.addAction(action)
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)

Note: IMP Line withRenderingMode(.alwaysOriginal)

Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
9

Try something like this:

UIAlertView* alert = [UIAlertView alloc] initWithTitle: @"Test Alert" message: @"Alert With Custom View" delegate:nil cancelButtonTitle:@"NO" otherButtonTitles:@"YES", nil];

UIImage* imgMyImage = [UIImage imageNamed:@"myImage.png"];
UIImageView* ivMyImageView = [UIImageView alloc] initWithFrame:CGRectMake(0, 0, imgMyImage.size.width, imgMyImage.size.height)];
[ivMyImageView setImage:imgMyImage];

[alert setValue: ivMyImageView forKey:@"accessoryView"];
[alert show];

Tested this and it works for iOS 7.0

enter image description here

PruitIgoe
  • 6,166
  • 16
  • 70
  • 137
1

Swift Version:

actionBtn.setValue(UIImage.init(named: "completeDose"), forKey: "image")
Dheeraj D
  • 4,386
  • 4
  • 20
  • 34
0

swift code

let customActionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

    let firstButton = UIAlertAction(title: "First Button", style: .default, handler: { action in
        //click action
    })
    firstButton.setValue(UIColor.black, forKey: "titleTextColor")
    firstButton.setValue(UIColor.black, forKey: "imageTintColor")
    firstButton.setValue(NSNumber(value: true), forKey: "checked")
    
    let secondButton = UIAlertAction(title: "Second Button", style: .default, handler: { action in
        //click action
    })
    
    secondButton.setValue(UIColor.black, forKey: "titleTextColor")
    let cancelButton = UIAlertAction(title: "Cancel", style: .cancel, handler: { action in
        //cancel
    })
    cancelButton.setValue(UIColor.black, forKey: "titleTextColor")
    
    customActionSheet.addAction(firstButton)
    customActionSheet.addAction(secondButton)
    customActionSheet.addAction(cancelButton)
    
    present(customActionSheet, animated: true)enter code here
Ashkar
  • 35
  • 7
-1

swift 3 extension , property and convenience init.

extension UIAlertAction{
    @NSManaged var image : UIImage?

    convenience init(title: String?, style: UIAlertActionStyle,image : UIImage?, handler: ((UIAlertAction) -> Swift.Void)? = nil ){
        self.init(title: title, style: style, handler: handler)
        self.image = image
    }
}

thanks to Shahar Stern for the inspiration

Benny Davidovitz
  • 1,152
  • 15
  • 18
  • You should not use NSManaged for non NSManagedObjects classes. The fact that under the hood the UIAlertAction responded to setImage does not make this snippet bullet proof. If the "under the hood" implementation changes this code would cause crash. – Giuseppe Lanza Mar 27 '17 at 12:24
  • Any use of undocumented api should be used with caution, And NSManager is the swift's dynamic (the one instead of synthesize) , do you have a different word to avoid setter and getter creation? – Benny Davidovitz Mar 27 '17 at 13:36
  • I agree with you about the use of undocumented api. Therefore if you don't want to use the image parameter with KeyValue approach, you have to create a custom object. simple as that. @NSManaged is for Core Data Object. Its side effect is that the getter performs valueForKey and the setter performs setValue:forKey:. This code is absolutely unsafe, and if the implementation of the image value changes in the future this will definitely lead to a crash. The short answer is "you should not do it anyway, as much as you should not use the private api" – Giuseppe Lanza Mar 27 '17 at 13:40