Adding an image to a UIAlertController - ios

This is my alert that works perfectly. I want to add an image to the alert that shows up along side the text when the alert is presented and I'm in an SKScene in SpriteKit if it makes a difference.
var alertController = UIAlertController(title: "How to Skate", message: "Tap the screen to perform a trick and jump over the obsticles (You can grind on rails) The game will end when you hit a highlighted red, orange or yellow obstacle. That's it! + Image", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Cool!", style: UIAlertActionStyle.Cancel, handler: nil))
self.view?.window?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)

You can add a UIImageView as a subview to your UIAlertController.
var imageView = UIImageView(frame: CGRectMake(220, 10, 40, 40))
imageView.image = yourImage
alert.view.addSubview(imageView)
This is how you do in UIAlertController:
let alertMessage = UIAlertController(title: "My Title", message: "My Message", preferredStyle: .Alert)
let image = UIImage(named: "myImage")
var action = UIAlertAction(title: "OK", style: .Default, handler: nil)
action.setValue(image, forKey: "image")
alertMessage .addAction(action)
self.presentViewController(alertMessage, animated: true, completion: nil)

let alertMessage = UIAlertController(title: "My Title", message: "", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default, handler: nil)
action.setValue(UIImage(named: "task1.png")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal), forKey: "image")
alertMessage .addAction(action)
self.present(alertMessage, animated: true, completion: nil)
Swift 3

You can do like this.
let imageView = UIImageView(frame: CGRectMake(220, 10, 40, 40))
// imageView.image = UIImage(named: "ic_no_data")
let alertMessage = UIAlertController(title: "My Title", message: "", preferredStyle: .Alert)
let image = UIImage(named: "Image")
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
action.setValue(image, forKey: "image")
alertMessage .addAction(action)
self.presentViewController(alertMessage, animated: true, completion: nil)
alertMessage.view.addSubview(imageView)

Adding an image to a UIAlertController
Please try below code Swift 4 +
Add alertView Controller
let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.alert)
let image = UIImage(named:"feet")!
alert.addImage(image: image)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
Add Extension UIAlertController
func addImage(image: UIImage) {
let maxSize = CGSize(width: 240, height: 244)
let imgSize = image.size
var ratio:CGFloat!
if (imgSize.width > imgSize.height){
ratio = maxSize.width / imgSize.width
}else {
ratio = maxSize.height / imgSize.height
}
let scaleSize = CGSize(width: imgSize.width*ratio, height: imgSize.height*ratio)
var resizedImage = image.imageWithSize(scaleSize)
if (imgSize.height > imgSize.width) {
let left = (maxSize.width - resizedImage.size.width) / 2
resizedImage = resizedImage.withAlignmentRectInsets(UIEdgeInsetsMake(0, -left, 0, 0))
}
let imgAction = UIAlertAction(title: "", style: .default, handler: nil)
imgAction.isEnabled = false
imgAction.setValue(resizedImage.withRenderingMode(.alwaysOriginal), forKey: "image")
self.addAction(imgAction)
}
Add image view extension
extension UIImage {
func imageWithSize(_ size:CGSize) -> UIImage {
var scaledImageRect = CGRect.zero
let aspectWidth:CGFloat = size.width / self.size.width
let aspectHeight:CGFloat = size.height / self.size.height
let aspectRatio:CGFloat = min(aspectWidth, aspectHeight)
scaledImageRect.size.width = self.size.width * aspectRatio
scaledImageRect.size.height = self.size.height * aspectRatio
scaledImageRect.origin.x = (size.width - scaledImageRect.size.width) / 2.0
scaledImageRect.origin.y = (size.height - scaledImageRect.size.height) / 2.0
UIGraphicsBeginImageContextWithOptions(size, false, 0)
self.draw(in: scaledImageRect)
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage!
}
}

If you're willing to use private APIs you could use the private attributedMessage property to set an attributed string as message containing an image:
Source: https://github.com/JaviSoto/iOS10-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIAlertController.h
let actionSheet = UIAlertController(title: "title", message: nil, preferredStyle: .actionSheet)
let str = NSMutableAttributedString(string: "Message\n\n", attributes: [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: .caption1), NSAttributedStringKey.foregroundColor: UIColor.gray])
let attachment = NSTextAttachment()
attachment.image = --> yourImage <--
str.append(NSAttributedString(attachment: attachment))
actionSheet.setValue(str, forKey: "_attributedMessage")
Again, this is a private API and therefore could change in any release without notice. To be used with caution!

SWIFT 4 +
let refreshAlert = UIAlertController(title: "Unlike Article", message: "Are you sure you want to unlike this Article?", preferredStyle: UIAlertControllerStyle.alert)
let cancel = UIAlertAction(title: "CANCEL", style: .default, handler: { (action: UIAlertAction!) in
return
})
let image = #imageLiteral(resourceName: "dislike_icon").resizedImage(newSize: CGSize(width: 25, height: 25))
let unLike = UIAlertAction(title: "UNLIKE", style: .destructive, handler: { (action: UIAlertAction!) in
self.articleUnLiking()
return
})
unLike.setValue(image.withRenderingMode(UIImageRenderingMode.alwaysOriginal), forKey: "image")
refreshAlert.addAction(cancel)
refreshAlert.addAction(unLike)
self.present(refreshAlert, animated: true, completion: nil)
NOTE :- Again, this is a private API and therefore could change in any release without notice. To be used with caution!
THANKS

Currently there isn't really a proper way of doing that with UIAlertController without using private api or other hacks because according to documentation you should not modify view hierarchy of alert view controller. So the best solution would be to create a custom view for that. However if you do not care about some additional borders then using attributed string in UITextField works:
alertController.addTextField { field in
let attachment = NSTextAttachment()
attachment.image = image
attachment.bounds = CGRect(x: 0, y: 0, width: 226, height: 226)
field.attributedPlaceholder = NSAttributedString(attachment: attachment)
field.textAlignment = .center
field.isEnabled = false
}

Related

Is it possible to change the Y-position of action sheet styled UIAlertController?

Current, I am showing action sheet style UIAlertController via the following code
#IBAction func attachmentButtonClicked(_ sender: Any) {
let chooseImageImage = UIImage(systemName: "photo")
let takePhotoImage = UIImage(systemName: "camera")
let drawingImage = UIImage(systemName: "paintbrush.pointed")
let recordingImage = UIImage(systemName: "mic")
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let chooseImageAction = UIAlertAction(title: "choose_image".localized, style: .default) {
UIAlertAction in
// Write your code here
}
chooseImageAction.setValue(chooseImageImage, forKey: "image")
let takePhotoAction = UIAlertAction(title: "take_photo".localized, style: .default) {
UIAlertAction in
// Write your code here
}
takePhotoAction.setValue(takePhotoImage, forKey: "image")
let drawingAction = UIAlertAction(title: "drawing".localized, style: .default) {
UIAlertAction in
// Write your code here
}
drawingAction.setValue(drawingImage, forKey: "image")
let recordingAction = UIAlertAction(title: "recording".localized, style: .default) {
UIAlertAction in
// Write your code here
}
recordingAction.setValue(recordingImage, forKey: "image")
let cancelAction = UIAlertAction(title: "Cancel".systemLocalized, style: .cancel) {
UIAlertAction in
// It will dismiss action sheet
}
alert.addAction(chooseImageAction)
alert.addAction(takePhotoAction)
alert.addAction(drawingAction)
alert.addAction(recordingAction)
alert.addAction(cancelAction)
// https://stackoverflow.com/questions/55653187/swift-default-alertviewcontroller-breaking-constraints
self.present(alert, animated: true, completion: nil)
}
The outcome is as following
I was wondering, is there a way to adjust the Y-position of UIAlertController, so that it will not block the bottom toolbar visibility? I wish the achieve the effect as shown in the following screenshot.
You need to find the subview and then change the constant of the bottom constraint.
\\-----OtherCode-----
if let bottomConstraint = alert.view.subviews[0].subviews.last?.constraints.first(where: { ($0.firstAttribute == .bottom) }) {
bottomConstraint.constant = bottomConstraint.constant - 50
}
self.present(alert, animated: true, completion: nil)

My Camera crash on ipad 12.1.4 but works fine on iphone

I am using the camera to take photo, it is working fine in iphone, but it crashes when i run it on ipad.
#IBAction func uploadPhotoButtonPressed(_ sender: UIButton) {
let camera = Camera(delegate_: self)
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let takePhoto = UIAlertAction(title: "Take Photo", style: .default) { (alert: UIAlertAction!) -> Void in
camera.PresentPhotoCamera(self, canEdit: true)
}
let sharePhoto = UIAlertAction(title: "Photo Library", style: .default) { (alert: UIAlertAction!) -> Void in
camera.PresentPhotoLibrary(self, canEdit: true)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (alert : UIAlertAction!) -> Void in
print("Cancel")
}
optionMenu.addAction(takePhoto)
optionMenu.addAction(sharePhoto)
optionMenu.addAction(cancelAction)
self.present(optionMenu, animated: true, completion: nil)
}
I think your error in UIAlertController because in iPad you need to pass source view.
Please check UIAlertController code for iPad
if let popoverController = yourAlert.popoverPresentationController {
popoverController.sourceView = self.view //to set the source of your alert
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) // you can set this as per your requirement.
popoverController.permittedArrowDirections = [] //to hide the arrow of any particular direction
}
You can check this code also in your simulator, please check first and resubmit your build.
Since Apple announce iOS app should run proper in ipad as well. so, we need to make sure when we capture photo from camera and select from photo library we also need to update code for iPad regarding UIImagePickerViewController. I am attaching code which works in both iPhone and iPad.
let actionSheetController: UIAlertController = UIAlertController(title: "Select Photo", message: "", preferredStyle: .actionSheet)
let cancelActionButton: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
print("Cancel")
}
actionSheetController.addAction(cancelActionButton)
let saveActionButton: UIAlertAction = UIAlertAction(title: "Photolibrary", style: .default)
{ action -> Void in
self.picker.allowsEditing = true
self.picker.sourceType = .photoLibrary
self.present(self.picker, animated: true, completion: nil)
}
actionSheetController.addAction(saveActionButton)
let deleteActionButton: UIAlertAction = UIAlertAction(title: "Camera", style: .default)
{ action -> Void in
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)
{
self.picker.allowsEditing = true
self.picker.sourceType = .camera
self.present(self.picker, animated: true, completion: nil)
}
}
actionSheetController.addAction(deleteActionButton)
if let popoverController = actionSheetController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
}
self.present(actionSheetController, animated: true, completion: nil)

Custom UIAlertController with image

I have a UIAlertController implementation with two actions:
let alert = UIAlertController(title: "Add your photo", message: "", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Add Later", style: .cancel) { (action) -> Void in }
let uploadAction = UIAlertAction(title: "Upload", style: .default) { (action) -> Void in }
alert.addAction(cancelAction)
alert.addAction(uploadAction)
present(alert, animated: true, completion: nil)
Now, I want to add an image (at center) below the title, with the two actions still being aligned as in the picture. What I have tried to do is create a UIImageView and add it to alertcontroller as:
let image = UIImage(named: "myimage.png")
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: alert.view.frame.width/2, y: alert.view.frame.height/2, width: 50, height: 50)
alert.view.addSubview(imageView)
But I cannot get it at the center of the alert. Is this the correct way? Or is there some other easy method to achieve this? How can I achieve this?
Use the following extension which allows to fully customise UIAlertController:-
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
}
}

How to create UIAlertView with Image

Hello everyone i have a question, if is possible to create UIAlertView with Image in Swift and how? If someone could help me because i don't find some example on network in swift practice all in objective c in iOS 6 not in iOS 7 or higher. Thanks.
After iOS8 UIAlertView is deprecated so Apple recommends you to use UIAlertController instead of UIAlertView. And to accomplish what you asked you can look here
Here is a workaround that I used successfully.
let myImage = UIImage(name:"myImage")
let prevImage = UIImageView(frame: CGRect(x: 10, y: 50, width: 250, height: 172))
prevImage.image = myImage
let spacer = "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
let previewController = UIAlertController(title: "PREVIEW", message: spacer, preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "SAVE", style: .Default) { (UIAlertAction) in
self.uploadPatientPhoto(myImage!)
}
let retakeAction = UIAlertAction(title: "RETAKE", style: .Default) { (UIAlertAction) in
self.retakeNewPatientPhoto(self)
}
let cancelAction = UIAlertAction(title: "CANCEL", style: .Cancel, handler: nil)
previewController.addAction(saveAction)
previewController.addAction(retakeAction)
previewController.addAction(cancelAction)
previewController.view.addSubview(prevImage)
presentViewController(previewController, animated: true, completion: nil)

Swift How to change UIAlertController's Title Color

How do I change the UIAlertController's Title font using Swift?
I'm not talking about the message color, I'm not talking about the buttons color.
I'm talking about the Title.
let attributedString = NSAttributedString(string: "Title", attributes: [
NSFontAttributeName : UIFont.systemFontOfSize(15), //your font here
NSForegroundColorAttributeName : UIColor.redColor()
])
let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
alert.setValue(attributedString, forKey: "attributedTitle")
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in
}
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
Added the correct line of code to my answer as it's much more concise than the answer below.
Alert(self, Title: “Hello”, TitleColor: UIColor.whiteColor(), Message: “World”, MessageColor: UIColor.whiteColor(), BackgroundColor: UIColor.blackColor(), BorderColor: UIColor.yellowColor(), ButtonColor: UIColor.yellowColor())
func Alert(View: ViewController, Title: String, TitleColor: UIColor, Message: String, MessageColor: UIColor, BackgroundColor: UIColor, BorderColor: UIColor, ButtonColor: UIColor) {
let TitleString = NSAttributedString(string: Title, attributes: [NSFontAttributeName : UIFont.systemFontOfSize(15), NSForegroundColorAttributeName : TitleColor])
let MessageString = NSAttributedString(string: Message, attributes: [NSFontAttributeName : UIFont.systemFontOfSize(15), NSForegroundColorAttributeName : MessageColor])
let alertController = UIAlertController(title: Title, message: Message, preferredStyle: .Alert)
alertController.setValue(TitleString, forKey: "attributedTitle")
alertController.setValue(MessageString, forKey: "attributedMessage")
let okAction = UIAlertAction(title: "OK", style: .Default) { (action) in
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: nil)
alertController.addAction(okAction)
alertController.addAction(cancelAction)
let subview = alertController.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
alertContentView.backgroundColor = BackgroundColor
alertContentView.layer.cornerRadius = 10
alertContentView.alpha = 1
alertContentView.layer.borderWidth = 1
alertContentView.layer.borderColor = BorderColor.CGColor
//alertContentView.tintColor = UIColor.whiteColor()
alertController.view.tintColor = ButtonColor
View.presentViewController(alertController, animated: true) {
// ...
}
}
What push25 said is correct, only you have to use key-value coding in order to set the attributed string. (Thanks dupuis2387)
//Define a color
let color = UIColor.redColor()
//Make a controller
let alertVC = UIAlertController(title: "Dont care what goes here, since we're about to change below", message: "", preferredStyle: UIAlertControllerStyle.Alert)
//Title String
var hogan = NSMutableAttributedString(string: "Presenting the great... Hulk Hogan!")
//Make the attributes, like size and color
hogan.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(40.0), range: NSMakeRange(24, 11))
hogan.addAttribute(NSForegroundColorAttributeName, value: color, range: NSMakeRange(0, NSString(string: hogan.string).length))
//Set the new title
//Use "attributedMessage" for the message
alertVC.setValue(hogan, forKey: "attributedTitle")
//This will change the button color
alertVC.view.tintColor = UIColor.orangeColor()
//Make the button
let button:UIAlertAction = UIAlertAction(title: "Label text", style: UIAlertActionStyle.Default, handler: { (e:UIAlertAction!) -> Void in
println("\(e)")
})
//You can add images to the button
let accessoryImage:UIImage = UIImage(named: "someImage")!
button.setValue(accessoryImage, forKey:"image")
//Add the button to the alert
alertVC.addAction(button)
//Finally present it
self.presentViewController(alertVC, animated: true, completion: nil)
I construct this class:
class Alert {
class func showAlert(title: String, titleColor: UIColor, message: String, preferredStyle: UIAlertControllerStyle, titleAction: String, actionStyle: UIAlertActionStyle, vc: UIViewController) {
let attributedString = NSAttributedString(string: title, attributes: [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 16), NSAttributedStringKey.foregroundColor: titleColor])
let alert = UIAlertController(title: title, message: message, preferredStyle: preferredStyle)
alert.setValue(attributedString, forKey: "attributedTitle")
alert.addAction(UIAlertAction(title: titleAction, style: actionStyle, handler: nil))
vc.present(alert, animated: true)
}
}
Usage
Alert.showAlert(title: "yourTitle", titleColor: .yourcolor, message: "your message", preferredStyle: .alert, titleAction: "your title action", actionStyle: .yourActionStyle, vc: self)
Hope this help :)
Here is for Swift 4 ++ also using a global instance for UIAlert
func showAlertError(withTitle title: String, withMessage message: String) {
var dialogTitle = title
if dialogTitle.isEmpty { dialogTitle = "Error:" }
let attributedString = NSAttributedString(string: dialogTitle, attributes: [
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15),
NSAttributedString.Key.foregroundColor : UIColor.red
])
let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)
alert.setValue(attributedString, forKey: "attributedTitle")
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(ok)
DispatchQueue.main.async(execute: {
self.present(alert, animated: true)
})
}
Also you can add a UIAlertAction with title " "(space) and add a custom UILabel to UIAlertController.view at the place of title.

Resources