I know that you can add a text field, but is it possible to add a label to a UIAlertController?
alertController.addTextFieldWithConfigurationHandler({(textField: UITextField!) in
textField.placeholder = "Hyperlink"
inputTextField = textField
inputTextField?.text="www.google.com"
})
^^Textfield
There is function for you:
func showAlertWith(withLabel: String) {
let alert = UIAlertController(title: "Hello!", message: "Hi everybody!\n", preferredStyle: UIAlertController.Style.alert )
let action = UIAlertAction(title: "Ok", style: .default)
alert.addAction(action)
present(alert, animated: true, completion: {
// Add your label
let margin:CGFloat = 8.0
let rect = CGRect(x: margin, y: 72.0, width: alert.view.frame.width - margin * 2.0 , height: 20)
let label = UILabel(frame: rect)
label.text = withLabel
label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5
alert.view.addSubview(label)
})
}
I didn't bother too much with the coordinates and options of the label inside the alert, but I think that the general meaning is clear to you.
This may solve your issue in much easier and flexible way.
https://github.com/wimagguc/ios-custom-alertview
The addSubview is not available in UIAlertView since iOS7. The view hierarchy for this class is private and must not be modified.
As a solution, this class creates an iOS-style dialog which you can extend with any UIViews or buttons. The animations and the looks are copied too and no images or other resources are needed.
Related
I have this code:
func alertBox(txt: String){
let ac = UIAlertController(title: "MyTtle" , message: "More information in my website: ", preferredStyle: .alert)
let ramkaNaObrazek = CGRect(origin: CGPoint(x: 10, y: 10), size: CGSize(width: 30, height: 30))
let ikonaAlertu = UIImageView(frame: ramkaNaObrazek)
ikonaAlertu.image = UIImage(named: "modal_podpowiedz")
ac.view.addSubview(ikonaAlertu)
ac.addAction(UIAlertAction(title: "Ok" , style: .cancel, handler: { (action: UIAlertAction!) in
}))
present(ac, animated: true)
}
I would like to add after this text: "More information in my website:" + www - a link to my website (http://www.myname.pl).
How can I do this?
You can't add custom fields like text views with clickable links to a UIAlertController. You will need to either create your own modal view controller that acts like a UIAlertController or use a third party framework that does it for you.
i have an AlertController with UITextView.
when UITexView become first responder the alter doesn't move up with the keyboard.
this is my code:
#IBAction func showAlert(sender: AnyObject) {
let alertController = UIAlertController(title: "Hello, I'm alert! \n\n\n\n\n\n\n", message: "", preferredStyle: .alert)
let rect = CGRect(x: 15, y: 15, width: 240, height: 150)//CGRectMake(15, 50, 240, 150.0)
let textView = UITextView(frame: rect)
textView.font = UIFont(name: "Helvetica", size: 15)
textView.textColor = UIColor.lightGray
textView.backgroundColor = UIColor.white
textView.layer.borderColor = UIColor.lightGray.cgColor
textView.layer.borderWidth = 1.0
textView.text = "Enter message here"
textView.delegate = self
alertController.view.addSubview(textView)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let action = UIAlertAction(title: "Ok", style: .default, handler: { action in
let msg = (textView.textColor == UIColor.lightGray) ? "" : textView.text
print(msg!)
})
alertController.addAction(cancel)
alertController.addAction(action)
self.present(alertController, animated: true, completion: {
textView.becomeFirstResponder()
})
}
and this is my result:
there is a solution?
thanks in advance
just addTextField and then remove it
alert.addTextField { field in
field.translatesAutoresizingMaskIntoConstraints = false
field.heightAnchor.constraint(equalToConstant: 0).isActive = true
}
let inCntrlr = alert.childViewControllers[0].view!
inCntrlr.removeFromSuperview()
and then you could add your own views. here is a
result
After presenting alert controller. Open keyboard for TextView and move alert controller up.
I hope this will suite for you.
self.present(alertController, animated: true, completion: {
textView.becomeFirstResponder()
UIView.animate(withDuration: 0.5, animations: {
alertController.view.frame.origin.y = 100
})
})
UIAlertController by default will slide up when they keyboard is shown. The problem here is that you have added a subview to the alert controller. From the UIAlertController docs:
The UIAlertController class is intended to be used as-is and does not
support subclassing. The view hierarchy for this class is private and
must not be modified.
Adding your own subview to the alert goes against what the docs say and is likely what is causing your problem. If you need an alert with a text view in it, your best bet is to create your own view and manage it yourself.
I created this drop-in replacement, also customizable for any special needs of course. It's pretty simple and 'just works'!
https://gist.github.com/unixb0y/42a1ae0fb707bdb5e1e484bafd33d44a
It is a subclass of UIAlertController with a UITextView inside.
When it is initialized, it observes keyboard changes and adjusts its view.frame.origin.y accordingly.
var keyboardHeight: CGFloat = 100 {
didSet {
let height = UIScreen.main.bounds.height
let menu = self.view.frame.height
let keyb = self.keyboardHeight
self.view.frame.origin.y = height-menu-keyb-20
}
}
...
...
...
#objc func keyboardChange(sender: Notification) {
guard let userInfo = sender.userInfo else { return }
let endFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
keyboardHeight = endFrame?.height ?? 100
}
It's like. You open keyboard and change alert position.
var alertController = UIAlertController(title: nil, message: nil, preferredStyle: UIAlertController.Style.alert)
var alertControllerPositon:CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#IBAction func showAlert(sender: AnyObject) {
let alertController = UIAlertController(title: "Hello, I'm alert! \n\n\n\n\n\n\n", message: "", preferredStyle: .alert)
let rect = CGRect(x: 15, y: 15, width: 240, height: 150)//CGRectMake(15, 50, 240, 150.0)
let textView = UITextView(frame: rect)
textView.font = UIFont(name: "Helvetica", size: 15)
textView.textColor = UIColor.lightGray
textView.backgroundColor = UIColor.white
textView.layer.borderColor = UIColor.lightGray.cgColor
textView.layer.borderWidth = 1.0
textView.text = "Enter message here"
textView.delegate = self
alertController.view.addSubview(textView)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let action = UIAlertAction(title: "Ok", style: .default, handler: { action in
let msg = (textView.textColor == UIColor.lightGray) ? "" : textView.text
print(msg!)
})
alertController.addAction(cancel)
alertController.addAction(action)
self.present(alertController, animated: true, completion: {
textView.becomeFirstResponder()
})
alertControllerPositon = alertController.view.frame.origin.y
}
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
alertControllerPositon = alertController.view.frame.origin.y
let result = self.view.frame.height - (alertController.view.frame.height + alertController.view.frame.origin.y) - 20
self.alertController.view.frame.origin.y -= (keyboardSize.height - result)
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if self.alertController.view.frame.origin.y != alertControllerPositon {
self.alertController.view.frame.origin.y = alertControllerPositon
}
}
let alert = UIAlertController(title: "Breaking Point Stack", message: "What's the average breaking point stack you have?", preferredStyle: UIAlertControllerStyle.alert)
alert.addTextField() { textField in
textField.backgroundColor = UIColor.clear
textField.useUnderLine()
}
self.present(alert, animated: true, completion: nil)
The text field is expected to show no background color and a white line at the bottom, however, when the alert controller is presented, the background of the text field is still white with a black border.
Here's the code for useUnderLine():
func useUnderLine() {
self.borderStyle = .none
self.layoutIfNeeded()
let border = CALayer()
let width = CGFloat(1.0)
border.borderColor = UIColor.white.cgColor
border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width)
border.borderWidth = width
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
The border & background style isn't decided by UITextField actually if you debug it by view hierarchy as Figure 1.
You do this change:
extension UITextField {
func useUnderLine() {
....
superview?.backgroundColor = .clear
let view = superview?.superview
view?.subviews.first?.alpha = 0
view?.backgroundColor = .clear
}
}
Modify the presending function too:
present(alert, animated: false, completion: {
if let textField = alert.textFields?.first {
textField.useUnderLine()
}
})
But aware that the View hierarchy might be different of different iOS version in the future.
Ok so I have this alert that I am using and I want the background of it to be black not grey like it is. I have managed to change the colour of the text for the title and the message but not the background colour. Well to the desired colour I want. I have changed it to green blue and white, but not black. When I try to change it to black it turns grey. Any suggestions will help and be appreciated. I tried this here How to change the background color of the UIAlertController? and that is how I got to where I am now.
Here is what I have going now:
func showAlert(title:String, message:String) {
//Set up for the title color
let attributedString = NSAttributedString(string: title, attributes: [
NSFontAttributeName : UIFont.systemFontOfSize(15), //your font here,
NSForegroundColorAttributeName : UIColor.whiteColor()
])
//Set up for the Message Color
let attributedString2 = NSAttributedString(string: message, attributes: [
NSFontAttributeName : UIFont.systemFontOfSize(15), //your font here,
NSForegroundColorAttributeName : UIColor.whiteColor()
])
let alert = UIAlertController(title: title,message: message, preferredStyle: .Alert)
alert.setValue(attributedString, forKey: "attributedTitle")
alert.setValue(attributedString2, forKey: "attributedMessage")
//alert.view.tintColor = UIColor.whiteColor()
let dismissAction = UIAlertAction(title: "Dismiss", style: .Destructive, handler: nil)
alert.addAction(dismissAction)
self.presentViewController(alert, animated: true, completion: nil)
//set the color of the Alert
let subview = alert.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
alertContentView.backgroundColor = UIColor.blackColor()
//alertContentView.backgroundColor = UIColor.greenColor()
//Changes is to a grey color :(
/*
alertContentView.backgroundColor = UIColor(
red: 0,
green: 0,
blue: 0,
alpha: 1.0)
//Also another Grey Color Not batman black
*/
//alertContentView.backgroundColor = UIColor.blueColor()
//turns into a purple
}
Swift 4.1 :
This is the best way works for me :
func testAlert(){
let alert = UIAlertController(title: "Let's See ..",message: "It Works!", preferredStyle: .alert)
let dismissAction = UIAlertAction(title: "Dismiss", style: .default, handler: nil)
// Accessing alert view backgroundColor :
alert.view.subviews.first?.subviews.first?.subviews.first?.backgroundColor = UIColor.green
// Accessing buttons tintcolor :
alert.view.tintColor = UIColor.white
alert.addAction(dismissAction)
present(alert, animated: true, completion: nil)
}
try this
Swift2 and below
let subview :UIView = alert.view.subviews. first! as UIView
let alertContentView = subview.subviews. first! as UIView
alertContentView.backgroundColor = UIColor.blackColor()
Objective -C
UIView *subView = alertController.view.subviews.firstObject; //firstObject
UIView *alertContentView = subView.subviews.firstObject; //firstObject
[alertContentView setBackgroundColor:[UIColor darkGrayColor]];
alertContentView.layer.cornerRadius = 5;
updated answer swift 3 and above
let alert = UIAlertController(title: "validate",message: "Check the process", preferredStyle: .alert)
let dismissAction = UIAlertAction(title: "Dismiss", style: .destructive, handler: nil)
alert.addAction(dismissAction)
self.present(alert, animated: true, completion: nil)
// change the background color
let subview = (alert.view.subviews.first?.subviews.first?.subviews.first!)! as UIView
subview.layer.cornerRadius = 1
subview.backgroundColor = UIColor(red: (195/255.0), green: (68/255.0), blue: (122/255.0), alpha: 1.0)
output
iPhone
iPad
Swift 5
Write just one line of code using UIAlertController extension.
alertController.setBackgroundColor(color: UIColor.black)
Full documentation: http://www.swiftdevcenter.com/change-font-text-color-and-background-color-of-uialertcontroller/
extension UIAlertController {
//Set background color of UIAlertController
func setBackgroundColor(color: UIColor) {
if let bgView = self.view.subviews.first, let groupView = bgView.subviews.first, let contentView = groupView.subviews.first {
contentView.backgroundColor = color
}
}
//Set title font and title color
func setTitlet(font: UIFont?, color: UIColor?) {
guard let title = self.title else { return }
let attributeString = NSMutableAttributedString(string: title)//1
if let titleFont = font {
attributeString.addAttributes([NSAttributedString.Key.font : titleFont],//2
range: NSMakeRange(0, title.utf8.count))
}
if let titleColor = color {
attributeString.addAttributes([NSAttributedString.Key.foregroundColor : titleColor],//3
range: NSMakeRange(0, title.utf8.count))
}
self.setValue(attributeString, forKey: "attributedTitle")//4
}
//Set message font and message color
func setMessage(font: UIFont?, color: UIColor?) {
guard let message = self.message else { return }
let attributeString = NSMutableAttributedString(string: message)
if let messageFont = font {
attributeString.addAttributes([NSAttributedString.Key.font : messageFont],
range: NSMakeRange(0, message.utf8.count))
}
if let messageColorColor = color {
attributeString.addAttributes([NSAttributedString.Key.foregroundColor : messageColorColor],
range: NSMakeRange(0, message.utf8.count))
}
self.setValue(attributeString, forKey: "attributedMessage")
}
//Set tint color of UIAlertController
func setTint(color: UIColor) {
self.view.tintColor = color
}
}
For Objective C, the below code works like charm.
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Save changes?" message:nil preferredStyle:UIAlertControllerStyleAlert];
UIView *firstSubview = alertController.view.subviews.firstObject;
UIView *alertContentView = firstSubview.subviews.firstObject;
for (UIView *subSubView in alertContentView.subviews) { //This is main catch
subSubView.backgroundColor = [UIColor blueColor]; //Here you change background
}
Due to a known bug (https://openradar.appspot.com/22209332), the accepted solution doesn't work on iOS 9.
See my full answer here: https://stackoverflow.com/a/37737212/1781087
In case someone wants to have an opaque white background color he can do this with this one liner:
UIVisualEffectView.appearance(whenContainedInInstancesOf: [UIAlertController.classForCoder() as! UIAppearanceContainer.Type]).backgroundColor = UIColor.white
Note however this will work properly only with white color as other colors will appear differently because of the default visual effect.
let subview = (alert.view.subviews.first?.subviews.first?.subviews.first!)! as UIView
subview.layer.cornerRadius = 1
subview.backgroundColor = UIColor.white
This image shows an alert view structure
If you want to change the background color you should change the 5th view's background color, for example, you can change it like this:
alert.view.subviews.forEach { v in
v.subviews.forEach { v in
v.subviews.forEach { v in
v.subviews.forEach { v in
v.backgroundColor = .black
}
}
}
}
I am currently implementing a UIAlertController with text inputs. I successfully made it without any issues. However, I want to change how it looks and especially add margins between textfields.
This is how it looks right now.
However I don't want these text fields that close. The question is, how do I add margins to textfields?
My code and attempt:
func createNameChangeSheet(){
var tvName : UITextField?
var tvSurname : UITextField?
let sheet = UIAlertController(title: "action", message: "alertView", preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "OK", style: .Default) { (action) in
self.changeNameSurname((tvName?.text)!,surname: (tvSurname?.text)!)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
sheet.addAction(saveAction)
sheet.addAction(cancelAction)
sheet.addTextFieldWithConfigurationHandler { (textField) in
tvName = textField
textField.text = self.name
let margins = UIEdgeInsets(top: 0, left: 0, bottom: 30, right: 0)
textField.layoutMargins = margins
}
sheet.addTextFieldWithConfigurationHandler { (textField) in
tvSurname = textField
textField.text = self.surname
}
self.presentViewController(sheet, animated: true) {}
}
in default UIAlertController views are not customizable, if you need customize output then we need to go for customviews or any thirdparty lib
An alternate to set bottom margin , make a UIView and addSubview to UITextField you can make an extension to use throughout the application.
extension UITextField {
func textbottommboarder(frame1 : CGRect){
let border = UIView()
let width = CGFloat(2.0)
border.backgroundColor = UIColor.lightGrayColor()
border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: frame1.width, height: 2)
self.layer.addSublayer(border.layer)
self.layer.masksToBounds = true
}
}
and than use it on UITextfields
txt_username.textbottommboarder(txt_username.frame)