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)
Related
In following code popover on iPad is not centred for second alert (cities) when iPad is rotated. It works fine for first alert (countries) though. I've printed the values and it's same for both alerts. It seems that despite having correct value for coordinates it doesn't present it in centre on device rotation for second alert.
Why it doesn't show in centre for second alert? How to fix it?
class MyVC: UIViewController {
var popoverController:UIPopoverPresentationController?
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
self.tableView.reloadData()
if self.popoverController != nil {
popoverController?.sourceView = self.view
print("viewWillTransition():width: x: \(UIScreen.main.bounds.size.width*0.5), y: \(UIScreen.main.bounds.size.height*0.5)")
popoverController?.sourceRect = CGRect(x: UIScreen.main.bounds.size.width*0.5, y: UIScreen.main.bounds.size.height*0.5, width: 0, height: 0)
popoverController?.permittedArrowDirections = []
}
}
#IBAction func countryButtonClicked(_ sender: UIBarButtonItem) {
displayCountries()
}
func displayCountries() {
let alert = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let titleAttributedText = NSMutableAttributedString(
string: "Select Country",
attributes: [
NSAttributedString.Key.paragraphStyle: paragraphStyle
]
)
alert.setValue(titleAttributedText, forKey: "attributedMessage")
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: countryHandler))
for list in Countries {
alert.addAction(UIAlertAction(title: list, style: .default, handler: countryHandler))
}
// For iPad
if let poController = alert.popoverPresentationController {
popoverController = poController
popoverController?.sourceView = self.view
print("displayCountries():width: x: \(UIScreen.main.bounds.size.width*0.5), y: \(UIScreen.main.bounds.size.height*0.5)")
popoverController?.sourceRect = CGRect(x: UIScreen.main.bounds.size.width*0.5, y: UIScreen.main.bounds.size.height*0.5, width: 0, height: 0)
popoverController?.permittedArrowDirections = []
}
alert.view.addSubview(UIView())
present(alert, animated: false, completion: nil)
}
#IBAction func cityButtonClicked(_ sender: Any) {
showCities()
}
func showCities(){
let alert = UIAlertController(title: "Select City", message: nil, preferredStyle: .actionSheet)
for listItem in Cities {
alert.addAction(UIAlertAction(title: listItem.title, style: .default, handler: cityHandler))
}
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: cityHandler))
if let popoverController = alert.popoverPresentationController {
popoverController.sourceView = self.view
print("showCities():width: x: \(UIScreen.main.bounds.size.width*0.5), y: \(UIScreen.main.bounds.size.height*0.5)")
popoverController.sourceRect = CGRect(x: UIScreen.main.bounds.size.width*0.5, y: UIScreen.main.bounds.size.height*0.5, width: 0, height: 0)
popoverController.permittedArrowDirections = []
}
alert.view.addSubview(UIView())
present(alert, animated: false, completion: nil)
}
}
popoverController must be also assigned in second alert:
if let popoverController = alert.popoverPresentationController {
self.popoverController = popoverController
...
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.
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.