How to display image in center of alert viewController with transparent background of alert viewController.
I wrote following code.
let image = UIImage(named: "ic_no_data")
let imageView = UIImageView(frame: CGRectMake(220, 10, 40, 40)
let alertMessage = UIAlertController(title: "image", message: "", preferredStyle: .Alert)
let backView = alertMessage.view.subviews.last?.subviews.last
backView?.layer.cornerRadius = 10.0
backView?.backgroundColor = UIColor.lightGrayColor()
alertMessage.view.addSubview(imageView)
let action = UIAlertAction(title:"", style: .Cancel, handler: nil)
action.setValue(image, forKey: "image")
alertMessage .addAction(action)
self.presentViewController(alertMessage, animated: true, completion: nil)
It looks like this.
Please help me to solve this problem and thanks to all.
UIAlertController doesn't support such changes in view hierarchy you'd be better using a custom extensible component that mimics the behavior of UIAlertController. The problem with UIAlertController is that you don't know how Apple will change its view hierarchy in the next version of iOS. And each time they change something you'll have to add code for a specific version of iOS which is really bad from the maintainability point of view.
For example CustomIOSAlertView: https://github.com/wimagguc/ios-custom-alertview.
you can store you reference of imageView an alertMessage, and in completion of the present viewController you have the exact size of the alert view, so you can adjust the image according to the current alert rect.
try this code is in swift3 :
self.present(alertMessage, animated: true, completion: {
var frame = self.alertMessage.view.frame
frame.origin = CGPoint(x: 0, y: 0) // add your location
self.imageView.frame = frame
})
Related
How to show keyboard when UIAlertController is present with Custom View and UITextField? I mean I want to keyboard automatically show without user touch the UITextField in alert view.
My code like below to make a Alert.
func callAlertConfirmation() {
let vc = UIViewController()
vc.preferredContentSize = CGSize(width: 250, height: 70)
let textBookmark = UITextField(frame: CGRect(x: 10, y: 0, width: 230, height: 40))
textBookmark.placeholder = "Typing folder name"
textBookmark.font = UIFont.systemFont(ofSize: 15)
textBookmark.textColor = UIColor.black
textBookmark.borderStyle = UITextField.BorderStyle.roundedRect
textBookmark.autocorrectionType = UITextAutocorrectionType.no
textBookmark.keyboardType = UIKeyboardType.alphabet
textBookmark.returnKeyType = UIReturnKeyType.done
textBookmark.contentVerticalAlignment = UIControl.ContentVerticalAlignment.center
textBookmark.textAlignment = NSTextAlignment.left
textBookmark.clearButtonMode = .whileEditing
vc.view.addSubview(textBookmark)
let alert = UIAlertController(title: "Create New Folder", message: nil, preferredStyle: .alert)
alert.setValue(vc, forKey: "contentViewController")
let actOKButton = UIAlertAction(title: "OK", style: .default) { (_) -> Void in
// action When User Okay
}
alert.addAction(actOKButton)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
alert.preferredAction = actOKButton
present(alert, animated: true)
}
And when I call
callAlertConfirmation
I get the result like this picture:
But I want to picture like below when I call
callAlertConfirmation
But when I use
alert.addTextField
I get keyboard automatically show when alert present.
Thanks in advance.
What
As #C4747N already said, you need to call
.becomeFirstResponder()
When
You want to call this method as you present the alert:
present(alert, animated: true) {
textBookmark.becomeFirstResponder()
}
The way you want to "read" this is like:
Present the alert and once you're done execute the completion body (make the alert's textField first responder)
I may be wrong but whenever I want a UITextView or UITextField to show a keyboard immediately i do:
textBookmark.becomeFirstResponder()
I have used a popoverPresentationController on iOS Swift and i have put both an image and text in the popover?
The issue i am having is that the content is too big for the popover? is it possible to set the dimensions?
Pictures are below of both the issue i am having and the trial code and error message?
let myAlert = UIAlertController(title: "\n\n\n\n\n\n", message: "Correct answer selected, move on to next level", preferredStyle: UIAlertControllerStyle.actionSheet)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default)
{
// action in self.dismiss(animated: true, completion: nil)
action in self.performSegue(withIdentifier: "goSegue1", sender: self)
self.musicEffect.stop()
}
// put image into action sheet
let imageView = UIImageView(frame: CGRect(x: 70, y: -30, width: 140, height: 140))
imageView.image = #imageLiteral(resourceName: "wellDone2.png")
myAlert.addAction(okAction);
myAlert.view.addSubview(imageView)
// display the alert messgae
myAlert.popoverPresentationController?.sourceView = view
myAlert.popoverPresentationController?.sourceRect = (sender as AnyObject).frame
myAlert.preferredContentSize = CGSize(width: 500, height: 800)
Issue
The size of the popover is not controlled by the PopoverPresentationController. The PopoverPresentationController only specifies how to present content, but the content itself, including size, is set by the view from which you have obtained the controller, in your case myAlert.
You have the right idea trying to set preferredContentSize, but you're setting it on the wrong view. You should change the line
popoverPresentationController?.preferredContentSize = /* ... */
to:
myAlert.preferredContentSize = /* ... */
This should solve the problem.
I'm creating a share sheet where someone can share the text from a text field. I've got it working on the iPhone, but the app crashes on the iPad. I know that it has to be in a popover form and have had this issue back in the day of Objective-C, but I can't seem to figure it out on Swift. This is my code that I've got going for the share sheet:
#IBAction func myShareButton(sender: AnyObject) {
// Hide the keyboard
textView.resignFirstResponder()
// Check and see if the text field is empty
if (textView.text == "") {
// The text field is empty so display an Alert
displayAlert("Warning", message: "You haven't written anything yet!")
} else {
// We have contents so display the share sheet
displayShareSheet(textView.text!)
}
}
// Show Warning
func displayAlert(title: String, message: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(alertController, animated: true, completion: nil)
return
}
// Display Share Sheet
func displayShareSheet(shareContent:String) {
let activityViewController = UIActivityViewController(activityItems: [shareContent as NSString], applicationActivities: nil)
presentViewController(activityViewController, animated: true, completion: {})
}
I implemented share sheets today as well and had the exact same issue. You need to add this before presenting.
if let popoverPresentationController = activityController.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: CGRectGetMidX(view.bounds), y: CGRectGetMidY(view.bounds), width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0) //Removes arrow as I dont want it
}
Line 1 sets the source view.
Line 2 I use to Center the popover right in the middle (I use it in SpriteKit and the popover is not attached to anything)
Line 3 I use to remove the arrow as I don't want it.
Hope this helps
for Swift 3/4
Depends on #crashoverride777 Answer
if let popoverPresentationController = activityVC.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0) //Removes arrow as I dont want it
}
there are many answers on Stack Overflow about this but none seem to work. how do you make the background color of a UIAlertViewController truly clear?
i have at the moment:
let errorAlert = UIAlertController(title: "Title", message: "Message", preferredStyle: UIAlertControllerStyle.Alert)
let subview = errorAlert.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
alertContentView.backgroundColor = UIColor.clearColor()
errorAlert.view.backgroundColor = UIColor.clearColor()
showViewController(errorAlert, sender: self)
but the result is a kind of white tinted, transparent-ish background over the image... is there anyway to remove this tinted background?
In order to achieve this the color of all subviews needs to be set to UIColor.clear. In addition, all UIVisualEffectView child views need to be removed. This can be accomplished by using a recursive function (Swift 4):
func clearBackgroundColor(of view: UIView) {
if let effectsView = view as? UIVisualEffectView {
effectsView.removeFromSuperview()
return
}
view.backgroundColor = .clear
view.subviews.forEach { (subview) in
clearBackground(of: subview)
}
}
Call this right after creating the UIAlertController instance:
let alert = UIAlertController(title: "Title", message: "Message", preferredStyle: .alert)
clearBackgroundColor(of: alert.view)
If you now want to change the appearance of the alert:
alert.view.layer.backgroundColor = UIColor.red.withAlphaComponent(0.6).cgColor
alert.view.layer.cornerRadius = 5
You need to access the superview of the UIAlertController
alertView.view.superview?.backgroundColor = UIColor.clearColor()
I found the following code in How to change the background color of the UIAlertController? to change the background color of a UIAlertView:
let subview = dialog.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
subview.subviews.top!
alertContentView.backgroundColor = UIColor.whiteColor()
However, it changes the background color of the entire view. How can I change only the background color of the title?
Try this out:
let alertController = UIAlertController(title: "", message: "myMessage", preferredStyle: .Alert)
let attributedString = NSAttributedString(string: "myTitle", attributes: [
NSFontAttributeName : UIFont.systemFontOfSize(15),
NSForegroundColorAttributeName : UIColor.redColor()
])
alertController.setValue(attributedString, forKey: "attributedTitle")
try with following its works for me.
let confirmAlert = UIAlertController(title: "Application Name", message: "This is demo message.", preferredStyle: .Alert)
let attributedString = NSAttributedString(string: "Application Name", attributes: [
NSFontAttributeName : UIFont.systemFontOfSize(13),
NSForegroundColorAttributeName : UIColor.greenColor()
])
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
confirmAlert.addAction(defaultAction)
confirmAlert.setValue(attributedString, forKey: "attributedTitle")
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(confirmAlert, animated: true, completion: nil)
Sample project -> Contains latest code
Step one:
Find a subview that has the right frame!
This little function will return the frame and address of all nested subviews.
We are looking for a subview that has a height that is smaller than that of the UIAlertController and has an Origin of 0,0.
Height of my alertController was 128
func subViewStack(view:UIView, levels: [Int]) {
var currentLevels = levels
currentLevels.append(0)
for i in 0..<view.subviews.count {
currentLevels[currentLevels.count - 1] = i
let subView = view.subviews[i]
print(subView.frame, "depth:", currentLevels)
subViewStack(subView, levels: currentLevels)
}
}
This prints stuff like this:
(0.0, 0.0, 270.0, 128.0) depth: [0, 0]
//frame - firstsubview - firstsubview
This might be a good candidate:
(0.0, 0.0, 270.0, 84.0) depth: [0, 1, 0, 0]
//frame - firstsubview - secondsubiew - firstsubview - firstsubview
This translates to this:
print(alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].frame)
// prints (0.0, 0.0, 270.0, 84.0) -> Bingo!
Step two:
Color that subview!
alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].backgroundColor = UIColor.redColor()
If you set the colour before presenting the alertController it will crash.
Setting it in the completionHandler works.
presentViewController(alertController, animated: true) { () -> Void in
self.subViewStack(alertController.view, levels: [])
print(alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].frame)
alertController.view.subviews[0].subviews[1].subviews[0].subviews[0].backgroundColor = UIColor.redColor()
}
Step three:
Make it safe!
If they ever change anything to the stack this will prevent your app from crashing. Your view might not be coloured but a crash is worse.
Extend UIView to be able to fetch subviews with one of the addresses we printed earlier. Use guardor if let to prevent accessing non-existent subviews.
extension UIView {
// use the printed addresses to access the views. This is safe even if the UIView changes in an update.
func getSubView(withAddress address:[Int]) -> UIView? {
var currentView : UIView = self
for index in address {
guard currentView.subviews.count > index else {
return nil
}
currentView = currentView.subviews[index]
}
return currentView
}
}
Step four:
Since it is not allowed to subclass UIAlertController we might try to extend it. This won't give you access to viewDidAppear so you can't display the UIAlertController animated.
protocol CustomAlert {
var view : UIView! { get }
}
extension CustomAlert {
func titleBackgroundColor(color:UIColor) {
if view == nil {
return
}
if let titleBackground = view.getSubView(withAddress: [0, 1, 0, 0]) {
titleBackground.backgroundColor = color
}
}
}
extension UIAlertController : CustomAlert {
}
This gives you both the method to find any subviews you might want to alter and a way to add a custom function for it to that class. Without subclassing.
Call titleBackgroundColor in the completionHandler of presentViewController to set the color.