Unable to choose order of buttons in UIAlertController - ios

I was under the impression that if the normal action is a destructive action and the other is a cancel action in their UIAlertController that the destructive one should be on the left and the cancel should be on the right.
If the normal action is not destructive, then the normal action should be on the right and the cancel should be on the left.
That said, I have the following:
var confirmLeaveAlert = UIAlertController(title: "Leave", message: "Are you sure you want to leave?", preferredStyle: .Alert)
let leaveAction = UIAlertAction(title: "Leave", style: .Destructive, handler: {
(alert: UIAlertAction!) in
//Handle leave
}
)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
confirmLeaveAlert.addAction(leaveAction)
confirmLeaveAlert.addAction(cancelAction)
self.presentViewController(confirmLeaveAlert, animated: true, completion: nil)
I was under the impression that if I add the leaveAction first, then the cancelAction that the leaveAction would be the button on the left. This was not the case. I tried adding the buttons in the opposite order as well and it also resulted in the buttons being added in the same order.
Am I wrong? Is there no way to achieve this?

My solution to this was to use the .Default style instead of .Cancel for the cancelAction.

Since iOS9 there is a preferredAction property on UIAlertController. It places action on right side. From docs:
When you specify a preferred action, the alert controller highlights the text of that action to give it emphasis. (If the alert also contains a cancel button, the preferred action receives the highlighting instead of the cancel button.)
The action object you assign to this property must have already been added to the alert controller’s list of actions. Assigning an object to this property before adding it with the addAction: method is a programmer error.

Related

How can I add custom textField to my alert?

I can add textField to my alert as shown below using alert.addTextField()
let alert = UIAlertController(title: "Title", message: "Subtitle", preferredStyle: UIAlertController.Style.alert)
alert.addTextField()
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: { _ in
print(alert.textFields?[0].text ?? "")
}))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
However, if I have a custom textField, like CurrencyField as shared in https://stackoverflow.com/a/29783546/3286489, how could I add that to my alert (instead of just having a generic TextField)?
The Holy Path
The Apple-given API doesn't allow for you to use a custom subclass of UITextField. It does, however, allow you to customize the UITextField:
alert.addTextField { textField in
// customize text field
}
You'll have to try and port the functionality of your CurrencyView over, having only access to the APIs available by default on UITextField.
The Unholy Path
⚠️ Disclaimer: This is a Bad Idea. Using vendor APIs in ways they weren't intended to makes your code and application less stable.
Now that we've got that out of the way: you could also add a view directly to the default UITextField. You'd have to disable interaction/editing on the original UITextField, though, and make sure it only goes to your custom text field.
If you really wanted to go to the dark side, you could swizzle UITextField and force your CurrencyView to be initialized, but, once again, this is a Bad Idea.

How to disable touch outside screen dismiss view using MDCAlertController Material Design - swift

I am new iOS programming and now am fascinated in using MaterialComponents which provide by google. Now i facing one problem in component named Dialog.
When the view has been pop up on screen when i touch outside that pop up view and then that view has been dismiss. I don't want that to happen in my app.
I don't want user to click outside popup view to dismiss that popup view. What i want i just want user to click on action button that i provide for user's choice then the view should be dismiss when click on that action button only.
Really glade that you help.
MDCAlertController is inherited from UIViewController.
So, in order to restrict user to click outside MDCAlertController you have to access its property named view and then superview?.subviews[0].isUserInteractionEnabled = false
I have completed one example using MDCAlertController
let alert = MDCAlertController(title: title, message: message)
alert.buttonTitleColor = UIColor(red:0.03, green:0.62, blue:0.09, alpha:1.0)
//MDCAlertControllerThemer.applyScheme(alertScheme, to: alert)
let okayAction = MDCAlertAction(title: "Okay") { (action) in
print("User click okay")
}
let cancelAction = MDCAlertAction(title: "Cancel", handler: nil)
alert.addAction(okayAction)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: {
// When the Dialog view has pop up on screen then just put this line of code when Dialog view has completed pop up.
alert.view.superview?.subviews[0].isUserInteractionEnabled = false
})
use this.
let alert = MDCAlertController(title: title, message: message)
alert.mdc_dialogPresentationController.dismissOnBackgroundTap = false
https://material.io/develop/ios/components/dialogs/api-docs/Categories/UIViewController_28MaterialDialogs_29.html
https://material.io/develop/ios/components/dialogs/api-docs/Classes/MDCDialogPresentationController.html#/c:objc(cs)MDCDialogPresentationController(py)dismissOnBackgroundTap

Cannot pop back in Navigation controller from Alert completion:

Swift 4, XCode 9.4
I cannot pop back to the root of the stack in the completion of (or even near) a UIAlertController.
The requirement is to show the user a confirmation and then directly transition back to the 'home' page. When I try I always get something like :
popToViewController:transition: called on <UINavigationController 0x7fc4fe85f000> while an existing transition or presentation is occurring; the navigation stack will not be updated.
I understand the concept I suppose. The UIAlertController is in control, or the nav controller is not sufficiently in control to pop back. Ok makes some sense since I am in the completion. But I don't see how to trigger my transition without being in there.
#IBAction func doneAction(_ sender: Any) {
if verifyDoneProperly() {
let alert = UIAlertController(title: "Complete", message: "Good Job", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: {
if let nav = self.navigationController {
nav.popToViewController(select, animated: true)
}
})
}
}
FWIW, It doesn't work when I specify the view controller either.
I have read carefully through this answer but nothing there is really going to help me (AFAIK).
The only thing I can really think to do is to send a message to the root controller and have it display the alert after having transitioned back (Perhaps checking for a flag in viewWillAppear)
There must surely be a correct way to do this. Can anyone suggest something?
Important Note: I cannot use segues here although I do have a storyboard. The transition to the 'worker' view controller is done programmatically and chosen based on the current state.
I'm not sure it's the best idea to pop a view controller while it's still presenting something else. And the completion of present is not executed after the view controller is dismissed, only after it has finished presentation (i.e., become visible on the screen).
You can pop your view controller in the handler of your OK action — which will be called after your view controller is no longer presenting the alert.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (_) in
self.navigationController?.popToViewController(select, animated: true)
}))
Make sure to perform the pop animation in the next run loop by embedding it in a dispatch block:
DispatchQueue.main.async {
self.navigationController?.popToViewController(select, animated: true)
}

No initializer for UIAlertAction (title, style, handler)

Dear Stackoverflowers,
Can any experts on Swift/UIKit see what I'm doing wrong in the following screenshot?
Xcode can't seem to find the convenience initializer for a UIAlertAction based on a title, style and handler, and I don't know of any other way to initialize a UIAlertAction. In practice, the handler won't be nil.
Thank you in advance,
Jamie
You are trying to pass Int to style param which is against swift rule. Try this out:
let saveAction = UIAlertAction(title: "Save", style: UIAlertActionStyle.Default, handler: nil)

Change title of button

I have an alertController with a button in it. Here's how I created the button:
var myButton : UIAlertAction!
// Later...
self.myButton = UIAlertAction(title: "myButton", style: .Default, handler: {action -> Void in
self.myButton.title = "✔︎\(myButton)"
})
After the button get's selected, I want to add a "✔︎" at the beginning of the title. (As you can see in the last line of code above.) When I try doing that, I get the following error:
Cannot assign to the result of this expression
What can I do to fix that? If myButtons title is read-only, then is there a valid workaround to it?
The error is not about the "✔︎". It's because of myButton. It means nothing to assign a UIAlertAction to String. That's how you get the error.

Resources