I am trying to create an dialog box to ask a file name to save.
Somehow the showed textfield has an extra space above and I cannot remove it. The space is not usable (it is not a line, just a top margin)
I couldn't get rid of it even by trying to change the .frame.height property of the textfield.
Please help! I don't understand why this is happening?
The ScreenShot: http://i.stack.imgur.com/dQYjz.png
The code is:
var fieldSetListName: UITextField!
func askForSetListName() {
//Create the AlertController
let alertController: UIAlertController = UIAlertController(title: "Name", message: "Enter a name for Setlist", preferredStyle: .Alert)
//Create and add the Cancel action
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { action -> Void in
//Do some stuff
}
alertController.addAction(cancelAction)
//Create and an option action
let okAction: UIAlertAction = UIAlertAction(title: "OK", style: .Default) { action -> Void in
//Do some other stuff
self.saveSetListAndDismiss(self.fieldSetListName.text)
}
alertController.addAction(okAction)
//Add a text field
alertController.addTextFieldWithConfigurationHandler { textField -> Void in
textField.textColor = UIPalette.DarkText
textField.placeholder = "(venue, festival, date etc.)"
self.fieldSetListName = textField
}
//Present the AlertController
self.presentViewController(alertController, animated: true, completion: nil)
}
Add textField like this:
var example :UITextField
var inputText : String
let exampletextField = actionSheetController.textFields![0] as UITextField
exampletextField.textColor = UIPalette.DarkText
exampletextField.placeholder = "(venue, festival, date etc.)"
inputText = exampletextField.text
Found the solution.
For anybody who comes across this kind of problem, setting rowHeight property of UITableView globally using UIAppearance effects the textfield height inside the alertview:
I got rid of the line: UITableView.appearance().rowHeight = 50
Related
I have an alert in my app where I put a textfield. The user can use it to add some values in an array. However I want all the values to be different. So if a user inserts an existing value, I want the textfield to be cleared and present a different placeholder text telling the user to insert a new value.
This is what I'm doing now:
func appendWord(){
let alertController = UIAlertController(title:"insert a word", message: nil, preferredStyle: UIAlertController.Style.alert)
alertController.addTextField { (textField : UITextField) -> Void in
textField.placeholder = "insert here"
textField.delegate = self
}
let cancelAction = UIAlertAction(title: "cancel", style: UIAlertAction.Style.cancel) { (result : UIAlertAction) -> Void in
}
let okAction = UIAlertAction(title: "save", style: UIAlertAction.Style.default) { (result : UIAlertAction) -> Void in
let newName = alertController.textFields![0].text! as String
//Useless Stuff to Append items here [...]
//If the item already exists then i call the following function which is inside of an if statement...
self.errorInCreation()
}
alertController.addAction(cancelAction)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
}
func errorInCreation(){
let alertController = UIAlertController(title:"Insert a new word", message: nil, preferredStyle: UIAlertController.Style.alert)
alertController.addTextField { (textField : UITextField) -> Void in
textField.placeholder = "The word already exists. Insert a new one"
textField.attributedPlaceholder = NSAttributedString(string: "The word already exists. Insert a new one",attributes: [NSAttributedString.Key.foregroundColor: UIColor.red])
textField.delegate = self
}
let cancelAction = UIAlertAction(title: "cancel", style: UIAlertAction.Style.cancel) { (result : UIAlertAction) -> Void in
}
let okAction = UIAlertAction(title: "save", style: UIAlertAction.Style.default) { (result : UIAlertAction) -> Void in
let newName = alertController.textFields![0].text! as String
//Useless Stuff to Append items here [...]
//If the item already exists then i call the following function which is inside of an if statement...
self.errorInCreation()
}
alertController.addAction(cancelAction)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
}
This should present a new alertViewController until the user inserts a new word. However this doesn't happen. When I press the save button, the alert closes.
I tried to edit the current alert but it's not really possible.
How could I clear the inserted text, change the placeholder name and let the user insert a new word?
I found this person who has my same problem but the solution pointed out here didn't work.
Presenting new AlertViewController after dismissing the previous AlertViewController - Swift
The solution is actually quite simple: don't use UIAlertController. It's just a specialized presented view controller, and you don't get much control over how it looks or behaves; in particular, it dismisses when a button is tapped, which is not what you want. So just use a custom presented view controller where you have the kind of control you're after.
I am using UIAlertController to getting name variable like this ;
In android my friends can put variables in Alert Controller when alert controller pops up comes like this;
they can put variables in text field and start with it.
But I couldn't, I tried to
alertController.textFields?.first?.text = myNameVariable
but it didn't work.
let alertController = UIAlertController(title: "Update Name", message: nil, preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Update", style: .default) { (_) in
if let txtField = alertController.textFields?.first, let text = txtField.text {
// operations
alertController.textFields?.first?.text = "Variable that i already have" // I want to change textfield content
print("Text==>" + text)
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.placeholder = "name"
}
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}))
sorry for uploading IBB instead of Imgur, in my country Imgur is blocked :/
You need to add the text field before you would access it
here is an example
let alertController = UIAlertController(title: "Update Name", message: nil, preferredStyle: .alert)
alertController.addTextField { textField in
textField.text = "Text goes here 1"
textField.placeholder = "placeholder"
textField.tag = 0
}
alertController.addTextField { textField in
textField.text = "Text goes here 2"
textField.tag = 1
}
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { _ in
let firstTextField = alertController.textFields?.first
let secondTextField = alertController.textFields?.last
print(firstTextField?.text, secondTextField?.text)
}))
Edit
Thanks to #rmaddy
The problem with question's code is that it's trying to set the text field's text after the alert has been dismissed. This makes little sense. Once a user taps one of the alert buttons, the user has already entered text into the text field. The code should be trying to read the user's entered text from the text field, not trying to update the text field's text.
I have a simple Parent Gateway for child friendly game using a UIAlertController.
When the user answers the question incorrectly - I DONT want the alert view to be dismissed, at the moment I have the device vibrate and the screen shake but I can't get the alert view to stay on the screen.
The answers provided are in Obj-C or involve disabling the button, which obviously won't work and the other answers do not work - so I was hoping there would be an updated answer.
func parentGate () {
var val1 = [1,2,3,4]
var val2 = [5,6,7,8]
let valIndex1 = Int(arc4random_uniform(UInt32(val1.count-1)))
let valIndex2 = Int(arc4random_uniform(UInt32(val2.count-1)))
accessAnswer = val1[valIndex1]+val2[valIndex2]
let alertController = UIAlertController (title: "Parental Control", message: "This section is for Parents only, \nplease answer the question below: \nWhat is \(val1[valIndex1]) + \(val2[valIndex2])?", preferredStyle: .alert)
let testAnswer = UIAlertAction(title: "OK", style: .default, handler: answerHandler)
let cancelAnswer = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addTextField(configurationHandler: answerTextFieldResult)
alertController.addAction(testAnswer)
alertController.addAction(cancelAnswer)
self.present(alertController, animated: true, completion: nil)
}
and then the testAnswer handler looks like this:
func answerHandler (alert: UIAlertAction) {
guard let suppliedAnswer = answerTextField?.text,
let answer = Int(suppliedAnswer) else {
return
}
if answer == accessAnswer {
print ("Good")
} else {
print ("Bad")
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
self.view.shake(count: 3, for: 0.3, withTranslation: 3)
}
}
If you want to see what the textField handler looks like at the moment:
func answerTextFieldResult(textfield: UITextField) {
answerTextField = textfield
answerTextField?.placeholder = "Answer"
}
You can't do this.
It's system behaviour - when you click on button alert closes and you can't prevent this.
Only one solution is to create a custom view controller that will look like native UIAlertController.
This is how I simply create UIAlertController and present it on the screen:
private class func showAlertWithTitle(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
//alert.accessibilityLabel = "my string here" //doesnt work
let action = UIAlertAction(title: "OK", style: .Default) { action in
alert.dismissViewControllerAnimated(true, completion: nil)
}
alert.addAction(action)
UIStoryboard.topViewController()?.presentViewController(alert, animated: true, completion: nil)
}
and this is how I access it under UITests:
emailAlert = app.alerts["First Name"] //for title "First Name"
but I would like to set there custom identifier and access this by firstName like this:
emailAlert = app.alerts["firstName"]
Is it possible?
This is an old thread but someone might use this.
I was able to set the accessibility identifier like this:
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.view.accessibilityIdentifier = "custom_alert"
alert.view.accessibilityValue = "\(title)-\(message)"
alert.addAction(
UIAlertAction(
title: "ALERT_BUTTON_OK".localized,
style: .default,
handler: handler
)
)
present(alert, animated: true)
That way I can access the alert by accessibility identifier and check its contents in accessibility value.
It is not perfect of course, but it works - at least for my testing using Appium.
The only way I figured out to do this was to use Apple's private APIs. You call valueForKey on the UIAlertAction object with this super secret key: "__representer" to get whats called a _UIAlertControllerActionView.
let alertView = UIAlertController(title: "This is Alert!", message: "This is a message!", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertView.addAction(okAction)
self.presentViewController(alertView, animated: true, completion: {
let alertButton = action.valueForKey("__representer")
let view = alertButton as? UIView
view?.accessibilityIdentifier = "okAction_AID"
})
This has to be done in the completion handler because that that _UIAlertControllerActionView won't exist until the view is presented. On a side note in my project I used these following extensions to make things easier / more readable:
extension UIAlertController {
func applyAccessibilityIdentifiers()
{
for action in actions
{
let label = action.valueForKey("__representer")
let view = label as? UIView
view?.accessibilityIdentifier = action.getAcAccessibilityIdentifier()
}
}
}
extension UIAlertAction
{
private struct AssociatedKeys {
static var AccessabilityIdentifier = "nsh_AccesabilityIdentifier"
}
func setAccessibilityIdentifier(accessabilityIdentifier: String)
{
objc_setAssociatedObject(self, &AssociatedKeys.AccessabilityIdentifier, accessabilityIdentifier, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
func getAcAccessibilityIdentifier() -> String?
{
return objc_getAssociatedObject(self, &AssociatedKeys.AccessabilityIdentifier) as? String
}
}
So the above code would be rewritten:
let alertView = UIAlertController(title: NSLocalizedString("NMN_LOGINPAGECONTROLLER_ERROR_TITLE", comment: ""), message: message as String, preferredStyle:.Alert)
let okAction = UIAlertAction(title: NSLocalizedString("NMN_OK", comment: ""), style: .Default, handler: nil)
okAction.setAccessibilityIdentifier(InvalidLoginAlertView_AID)
alertView.addAction(okAction)
self.presentViewController(alertView, animated: true, completion: {
alertView.applyAccessibilityIdentifiers()
})
My first attempt involved trying to navigate the view hierarchy but that became difficult since UIAlertControllerActionView was not a part of the public API. Anyway I'd probably would try to ifdef out the valueForKey("__representer") for builds submitted for the app store or Apple might give you a spanking.
Right now I have a UIAlertAction called addCamera and I'm just doing:
addCamera.accessibilityLabel = "camera-autocomplete-action-photo"
That allows me to tap it in UI Tests as follows:
app.sheets.buttons["camera-autocomplete-action-photo"].firstMatch.tap()
From Apple docs...
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UIAlertView.html
Making Alert Views Accessible
Alert views are accessible by default.
Accessibility for alert views pertains to the alert title, alert message, and button titles. If VoiceOver is activated, it speaks the word “alert” when an alert is shown, then speaks its title followed by its message if set. As the user taps a button, VoiceOver speaks its title and the word “button.” As the user taps a text field, VoiceOver speaks its value and “text field” or “secure text field.”
I have an UIAlertController and i'm checking for user input. When the user doesn't type in text field, the OK Action button i added should give the user a warning and not close the alert view.
I handle the warning but the alert view closes automatically.
How can i disable the automatic closing?
Thanks.
MY CODE:
var alert = UIAlertController(title: "change name and phone number", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default,
handler: { action in
//Add a comment to this line
let nameField: UITextField = alert.textFields![0] as UITextField
let phoneField: UITextField = alert.textFields![1] as UITextField
let name = nameField.text
let phone = phoneField.text
if name.length == 0 {
JLToast.makeText("Please enter name").show()
} else if phone.length == 0 {
JLToast.makeText("Please enter phone number").show()
} else {
self.sendSupportInfo(nameField.text, phone: phoneField.text)
}
println("name:: \(nameField.text), phone: \(phoneField.text)")
}))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Default, handler: nil))
alert.addTextFieldWithConfigurationHandler { (textField) -> Void in
textField.placeholder = "name"
}
alert.addTextFieldWithConfigurationHandler { (textField) -> Void in
textField.placeholder = "0544-444444"
textField.keyboardType = UIKeyboardType.PhonePad
}
self.presentViewController(alert, animated: true, completion: nil)
You can not do that.
Other option is, you can only disable the UIAlertAction.
Instead, you might want to create your own custom dialog to that.
as the offical documentation say:
Subclassing
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.
U can create a new UI window and make the window level above the alert level and then show your alert onto the new UIwindow.