I'm trying to use a UIAlertController for multiple purposes. It has two buttons, cancel and OK. I would like to add it to a method and return the button press, so I could just check for the user's response and act on it.
Now, I can't return a value inside block. So, how would I go about this?
Thanks.
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(#"Atenção!", "Atenção!") message:NSLocalizedString(#"Você não finalizou a sua série. Se sair desta tela, irá zerar o cronômetro.", "") preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelar = [UIAlertAction actionWithTitle:NSLocalizedString(#"Cancelar", "Cancelar") style:UIAlertActionStyleCancel handler:^(UIAlertAction *action)
{
[alertController dismissViewControllerAnimated:YES completion:nil];
// I would like to return this button press to the method calling this one.
}];
[alertController addAction:cancelar];
UIAlertAction *ok = [UIAlertAction actionWithTitle:NSLocalizedString(#"OK", "OK") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action)
{
[alertController dismissViewControllerAnimated:YES completion:nil];
// I would like to return this button press to the method calling this one.
}];
[alertController addAction:ok];
[self presentViewController:alertController animated:YES completion:nil];
UPDATE: Real use
When user presses back button, it will call a method to check a condition. If the condition is met, the alert is shown and user needs to decide to leave screen or not. That's why it would be great to return the answer to the IBAction back Button.
Note: The whole idea is to have other methods, besides the back Button, also show the alert and get an response from user.
You can make use of blocks.
Create a method like this
- (void)alertWithResponse:(void (^)(BOOL didCancel))response {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(#"Atenção!", "Atenção!") message:NSLocalizedString(#"Você não finalizou a sua série. Se sair desta tela, irá zerar o cronômetro.", "") preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelar = [UIAlertAction actionWithTitle:NSLocalizedString(#"Cancelar", "Cancelar") style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
[alertController dismissViewControllerAnimated:YES completion:nil];
response(YES);
}];
[alertController addAction:cancelar];
UIAlertAction *ok = [UIAlertAction actionWithTitle:NSLocalizedString(#"OK", "OK") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[alertController dismissViewControllerAnimated:YES completion:nil];
response(NO);
}];
[alertController addAction:ok];
[self presentViewController:alertController animated:YES completion:nil];
}
Now in your back button, call this method like this
- (IBAction)backButtonCliccked:(id)sender {
//your button logic...
//.
//.
//.
[self alertWithResponse:^(BOOL didCancel) {
if(didCancel) {
//alert returned Cancel
} else {
//alert returned OK
}
}];
}
Related
in my app i have tableview and for clear all cells i given an action to clear button.
button work correctly and all cell deleted. but i want to give a option to user to canceled
i used UIAlertController class and its work only one time after i chosen delete button.(its work every time if i chosen cancel button)
warning in console:
Warning:
Attempt to present UIAlertController on HistoryViewController which is already presenting UINavigationController
- (IBAction)showNormalActionSheet:(id)event
{
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:NSLocalizedString(#"Cancel", #"Cancel action")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
NSLog(#"Cancel action");
}];
UIAlertAction *resetAction = [UIAlertAction
actionWithTitle:NSLocalizedString(#"Clear all recent", #"Reset action")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *action)
{
[self onDeleteClick];
NSLog(#"Reset action");
}];
[alertController addAction:resetAction];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
//- (IBAction)onDeleteClick:(id) event {
- (void)onDeleteClick {
linphone_core_clear_call_logs([LinphoneManager getLc]);
[tableController loadData];
editButton.hidden = ([tableView.dataSource tableView:tableView numberOfRowsInSection:0] == 0);
if(editButton.selected) {
[editButton toggle];
[self onEditClick:nil];
}
}
I have made an ActionSheet like this:
Now I want change the color Cancel And Delete to give the feel like they are disabled.
I am able to change the color of all buttons but not individuals.
I have tried using categories but I am keep getting warining that ActionSheet is Depreciated. And the code didn't work also.
I have written this Code:
- (void)setButton:(NSInteger)buttonIndex toState:(BOOL)enabled {
for (UIView* view in self.subviews)
{
if ([view isKindOfClass:[UIButton class]])
{
if (buttonIndex == 0) {
if ([view respondsToSelector:#selector(setEnabled:)])
{
UIButton* button = (UIButton*)view;
button.enabled = enabled;
}
}
buttonIndex--;
}
}
}
Is it possible to give disabled look to some of the buttons of Action sheet presented via AlertViewController.
Below is the my code to present Action Sheet:
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:#"Action Sheet" message:#"Using the alert controller" preferredStyle:UIAlertControllerStyleActionSheet];
[actionSheet.view setTintColor:[UIColor redColor]];
[actionSheet addAction:[UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
// Cancel button tappped.
[self dismissViewControllerAnimated:YES completion:^{
}];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:#"Delete" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
// Distructive button tapped.
[self dismissViewControllerAnimated:YES completion:^{
}];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:#"Group 1" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
// Distructive button tapped.
[self dismissViewControllerAnimated:YES completion:^{
}];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
// OK button tapped.
[self dismissViewControllerAnimated:YES completion:^{
}];
}]];
// Present action sheet.
[self presentViewController:actionSheet animated:YES completion:nil];
What you can do is use the setEnabled property of UIAlertAction.
This will render your button as 'greyed out'.
I have modified a piece of your code to incorporate this change:
UIAlertAction *action = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
// OK button tapped.
[self dismissViewControllerAnimated:YES completion:^{
}];
}];
[action setEnabled:NO];
[actionSheet addAction:action];
Ofcourse, you can't click on the button after you disable it.
Other options would involve using UIAlertActionStyle.
There are three:
UIAlertActionStyleDefault,
UIAlertActionStyleCancel,
UIAlertActionStyleDestructive
UIAlertActionStyleDefault will render your button with tintColor.
UIAlertActionStyleCancel will render your button on the bottom of the sheet.
UIAlertActionStyleDestructive renders your button with a 'red' color. (Think: Delete button)
Get the actions array and change the state for the action you want.
This way you can change the state even after adding the action.
Here is the sample code.
NSArray* actionlist = actionSheet.actions;
UIAlertAction * action2 = [actionlist objectAtIndex:1];
action2.enabled = false;
// Present action sheet.
[self presentViewController:actionSheet animated:YES completion:nil];
Try to use the code from the first answer in the link (by Kampai):
How to use UIAlertController to replace UIActionSheet?
However, the completion handler is not even called in my code.
The alert action sheet can be dismissed after pressing both buttons but nothing inside the completion handler works.
Any idea what might be the problem? I'm new to using completion handler and have tried to find answers online, but few have the same problem as mine.
- (IBAction)takePhotoButtonPressed:(UIButton *)sender {
pressedButtonTagNumber = sender.tag;
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[actionSheet addAction:[UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
// Cancel button tappped
[self dismissViewControllerAnimated:YES completion:^{
}];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:#"Take a Photo" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSLog(#"!");
// Take a Photo button tapped
[self dismissViewControllerAnimated:YES completion:^{
NSLog(#"0"); // NOT CALLED
// Initialize UIImagePickerController
UIImagePickerController *takePhotoImagePickerController = [[UIImagePickerController alloc] init]; takePhotoImagePickerController.delegate = self;
takePhotoImagePickerController.allowsEditing = YES;
NSLog(#"1");
// Check and assign image source
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
NSLog(#"2");
UIAlertController *noCameraErrorSheet = [UIAlertController alertControllerWithTitle:#"Camera is not available" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[noCameraErrorSheet addAction:[UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
// Cancel button tappped
[self dismissViewControllerAnimated:YES completion:^{
}];
}]];
} else {
takePhotoImagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
// Present UIImagePickerController
[self presentViewController:takePhotoImagePickerController animated:YES completion:NULL];
}
}];
}]];
Solution:
#Paulw11 solution works great:
1) No need to dismissViewController for UIAlertController.
2) Cannot call a new UIAlertController if the one wraps it is dismissing (obviously).
3) Better to check and disable the button in advance.
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[actionSheet addAction:[UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
}]];
UIAlertAction *takePhotoActionButton = [UIAlertAction actionWithTitle:#"Take Photo" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self takePhoto];
}];
UIAlertAction *uploadPhotoActionButton = [UIAlertAction actionWithTitle:#"Upload from Library" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self uploadPhoto];
}];
// Disable take a photo button if source not available
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[takePhotoActionButton setEnabled:FALSE];
}
// Disable upload a photo button if source not available
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
[uploadPhotoActionButton setEnabled:FALSE];
}
[actionSheet addAction:takePhotoActionButton];
[actionSheet addAction:uploadPhotoActionButton];
// Present action sheet.
[self presentViewController:actionSheet animated:YES completion:nil];
You don't need to call dismissViewController:animated: from within the action handler to remove the alert. UIAlertController calls this to dismiss itself prior to invoking the action handler code.
In your action handler you simply need to execute whatever should be done when that action is selected:
In this case:
In your cancel action you don't need to do anything
In your "take a photo" action you take a photo
Also, from a user experience point of view, it may be better to disable the "take a photo" or present an alert as soon as they select it rather than issuing an alert after they have attempted to take a photo; in other words indicate the problem earlier rather than later
I just apply a switch on my viewcontroller and I define a method to get called when the switch is get on
-(void)switchIsChanged:(UISwitch *)paramsender{
if ([paramsender isOn]) {
UIAlertController *alertView = [UIAlertController alertControllerWithTitle:#"Alert" message:#"Are you sure" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}];
[alertView addAction:defaultAction];
[self presentViewController:alertView animated:YES completion:nil];
}
}
this is the method but I just want to call this whole alert thing in a method. How can I do it?
Use this ::
UISwitch *swi; //however you get your switch, as a storyboard component or initialized in your code
[swi addTarget:self action:#selector(switchIsChanged:) forControlEvents:UIControlEventValueChanged];
I am using Objective-C to write about some UIAlertController code.
I have more buttons, but the buttons will show different UIAlertControllers and deal with different UIAlertAction handler .
So I want to create one UIAlertController,and UIAlertAction.
Like below:
-(void) initAlert{
alertController = [UIAlertController alertControllerWithTitle:#"hint" message:#"count down alert" preferredStyle:UIAlertControllerStyleAlert];
doneAction = [UIAlertAction actionWithTitle:#"okey" style:UIAlertActionStyleDefault handler:
^(UIAlertAction *action) {
NSLog(#"show log");
}];
[alertController addAction:doneAction];
}
-(void) showAlert{
[self presentViewController:alertController animated:YES completion:nil];
}
Then I want to using different button IBAction to call the showAlert method, and set different UIAlertController title, UIAlertAction title and deal different alertAction handler.
But I encounter some problems.
I call the method in different button like below:
- (IBAction)btn1Action:(UIButton *)sender {
alertController.title = #"controller 1";
alertController.message = #"message1";
[self showAlert];
}
- (IBAction)btn2Action:(UIButton *)sender {
alertController.title = #"controller 2";
alertController.message = #"message2";
[self showAlert];
}
I don't know how to change the UIAlertAction title with the same doneAction, I search some data show the UIAlertAction is readyonly property.
So have any other methods to change UIAlertAction title? or can we delete the UIAlertController addAction: method to add other UIAlertAction?
And how can I pass different UIAlertAction handler to AlertAction for the same UIAlertController to use?
Thank you very much.
UIAlertController should not be used multiple times. Just use a new UIAlertController instance each time you want to pop up the alert.
- (IBAction)btn1Action:(UIButton *)sender {
[self showAlert:#"Controller 1" message:#"Message 1" handler:^(UIAlertAction *action) {
NSLog(#"btn1Action");
}];
}
- (IBAction)btn2Action:(UIButton *)sender {
[self showAlert:#"Controller 2" message:#"Message 2" handler:^(UIAlertAction *action) {
NSLog(#"btn2Action");
}];
}
-(void)showAlert:(NSString*)alertTitle message:(NSString*)message handler:(void (^ __nullable)(UIAlertAction *action))handler {
UIAlertController * alertController = [UIAlertController alertControllerWithTitle:alertTitle message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction * doneAction = [UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:handler];
[alertController addAction:doneAction];
[self presentViewController:alertController animated:YES completion:nil];
}