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
}
}
}
}
Related
I am currently developing an iOS application.
I have customized my alerts to match the colors of my app.
Here is the code:
func createPopUp(title: String, message: String, preferredStyle: UIAlertController.Style) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: preferredStyle)
alert.setTitlet(font: UIFont.boldSystemFont(ofSize: 17), color: UIColor.customOrange)
alert.setMessage(font: UIFont.systemFont(ofSize: 13), color: UIColor.customOrange)
let subview = alert.view.subviews.first! as UIView
let alertContentView = subview.subviews.first! as UIView
alertContentView.backgroundColor = UIColor.black // This is the important line
alertContentView.tintColor = UIColor.customOrange
alertContentView.layer.cornerRadius = 15;
return alert
}
Only when I launch the app, I get this rendering:
RenderingBlack
The background color is not black. However when I change the UIColor, for example :
alertContentView.backgroundColor = UIColor.green
The rendering is correct:
RenderingGreen
In spite of research on the net I can't find the solution.
Thanks for your time :)
Hello fiend please replace
alertContentView.backgroundColor = UIColor.black
with alert.view.subviews.first?.subviews.first?.subviews.first?.backgroundColor = .black
It will solve your problem.
here the screenshot that I want output please check
I want the result like this search bar with background color white and black border
here my code is
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
for subView in searchBar.subviews {
if !subView.subviews.contains(where: { $0 as? UITextField != nil }) { continue }
guard let textField = subView.subviews.first(where: { $0 as? UITextField != nil }) as? UITextField else { return }
let placeholder = NSMutableAttributedString(
string: "Search",
attributes: [.font: UIFont(name: "Helvetica", size: 15.0)!,
.foregroundColor: UIColor.gray
])
textField.attributedPlaceholder = placeholder
textField.layer.cornerRadius = textField.frame.size.height / 2
textField.layer.masksToBounds = true
textField.textColor = .black
textField.backgroundColor = .white
}
this is my output screenshot please check it
I am unable to set search bar, please suggest me
Good day! If I understand you correctly, then this may solve your problem. Extension for UISearchBar (Swift 5):
import UIKit
extension UISearchBar {
func setupSearchBar(background: UIColor = .white, inputText: UIColor = .black, placeholderText: UIColor = .gray, image: UIColor = .black) {
self.searchBarStyle = .minimal
self.barStyle = .default
// IOS 12 and lower:
for view in self.subviews {
for subview in view.subviews {
if subview is UITextField {
if let textField: UITextField = subview as? UITextField {
// Background Color
textField.backgroundColor = background
// Text Color
textField.textColor = inputText
// Placeholder Color
textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder ?? "", attributes: [NSAttributedString.Key.foregroundColor : placeholderText])
// Default Image Color
if let leftView = textField.leftView as? UIImageView {
leftView.image = leftView.image?.withRenderingMode(.alwaysTemplate)
leftView.tintColor = image
}
let backgroundView = textField.subviews.first
backgroundView?.backgroundColor = background
backgroundView?.layer.cornerRadius = 10.5
backgroundView?.layer.masksToBounds = true
}
}
}
}
// IOS 13 only:
if let textField = self.value(forKey: "searchField") as? UITextField {
// Background Color
textField.backgroundColor = background
// Text Color
textField.textColor = inputText
// Placeholder Color
textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder ?? "", attributes: [NSAttributedString.Key.foregroundColor : placeholderText])
// Default Image Color
if let leftView = textField.leftView as? UIImageView {
leftView.image = leftView.image?.withRenderingMode(.alwaysTemplate)
leftView.tintColor = image
}
}
}
}
Also, you can try to do it with an image.
The way to do this only using Apple APIs is to create an image and use setSearchFieldBackgroundImage:
self.searchBar.setSearchFieldBackgroundImage(UIImage(named: "SearchFieldBackground"), for: UIControlState.normal)
Source: Cannot change search bar background color
I faced the following problem.
I set a background color of an action sheet.
For iPhone everything works fine, but the iPad version shows an alert without any text in it (alert is completely filled with a color i set).
Is it an apple bug or do i do something wrong?
#IBAction func save(_ sender: UIButton) {
let alert = UIAlertController(title: nil, message: "Error", preferredStyle: .actionSheet)
alert.view.tintColor = .black
alert.popoverPresentationController?.sourceView = self.view
alert.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
self.present(alert, animated: true)
}
What's wrong is the idea that you are going to modify a UIAlertController. It does what it does and looks the way it looks and you should not try to mess with that. If you want something that is custom but looks and acts like a UIAlertController, then make one, yourself (a presented UIViewController).
You can write an extension to UIAlertController like this.
extension UIAlertController {
//Set background color
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 setTitleColorAndFont(font: UIFont? = UIFont.boldSystemFont(ofSize: 17.0), color: UIColor?) {
guard let title = self.title else { return }
let attributeString = NSMutableAttributedString(string: title)
if let titleFont = font {
attributeString.addAttributes([NSAttributedString.Key.font: titleFont],
range: NSRange(location: 0, length: title.utf8.count))
}
if let titleColor = color {
attributeString.addAttributes([NSAttributedString.Key.foregroundColor: titleColor],
range: NSRange(location: 0, length: title.utf8.count))
}
self.setValue(attributeString, forKey: "attributedTitle")
}
//Set message font and message color
func setMessageColorAndFont(font: UIFont? = UIFont.systemFont(ofSize: 13.0), 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: NSRange(location: 0, length: message.utf8.count))
}
if let messageColorColor = color {
attributeString.addAttributes([NSAttributedString.Key.foregroundColor: messageColorColor],
range: NSRange(location: 0, length: message.utf8.count))
}
self.setValue(attributeString, forKey: "attributedMessage")
}
}
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.