Why clickedButtonAtIndex method is call even tap on out side of UIActionSheet? - ios

As my title said that clickedButtonAtIndex delegate method is call even tap on out side of UIActionSheet.
My actionSheet is display when I tapped on UIButton.
Code of my UIActionSheet declaration.
-(void)btnComplexityTapped:(UIButton *) sender
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Select your complexity" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Easy", #"Medium", #"High", nil];
[actionSheet showFromRect:sender.frame inView:self.view animated:YES];
[actionSheet release];
}
And in delegate method
- (void)actionSheet:(UIActionSheet *)myActionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 0)
{
[self.btnComplexity setTitle:#"Easy" forState:UIControlStateNormal];
}
else if(buttonIndex == 1)
{
[self.btnComplexity setTitle:#"Medium" forState:UIControlStateNormal];
}
else
{
[self.btnComplexity setTitle:#"High" forState:UIControlStateNormal];
}
}
I know that this issue is fix by set last condition in delegate method to set else if(buttonIndex == 1) instead of only else. But I does not want to apply any fixing but I want to know why delegate method is called even I am not tapping on any button of UIActionSheet
See this video for more clear picture.
As above video default title of button is "Medium" when I click on button then actionSheet is open and I click on out side of actionSheet (such like self.view) then delegate method clickedButtonAtIndex is called so last else condition is become true and thats way my button's title is changed "High".
Can any body tell my why this is happening ?

In iPad action sheet is presented in a popover. No cancel button because touching out of popover is equivalent to a touch on cancel. So, your delegate receives the message as if cancel button has been touch.

Because it is presented in POPOVER (iPad) which does not have cancel button on ActionSheet.Its Cancel is triggered if you tap out of ActionSheet.

Related

UIActionSheet throws ViewController actionSheet:clickedButtonAtIndex

I am using XCode 5.1.1 for development purposes and using the iOS simulator to test my app.
I have an action sheet that has Save, Cancel and Delete options. I haven't yet coded the action handling for Save and Delete, but tapping on cancel should go back to the previous screen (I have used navigation controller to move between screens). But tapping on cancel, throws me "ViewController actionSheet:clickedButtonAtIndex:]: message sent to deallocated instance" error, which I am not able to solve. I have hooked up all the elements to their outlets/actions correctly. Below is my code. Please help. (I am trying to display the action sheet when a "return" button is clicked. And in the action sheet, when I tap cancel, the previous screen had to be displayed - I guess this can be done by dismissViewControllerAnimated which dismisses the current controller and displays the previous controller.)
-(IBAction)returnModalAction:(id)sender {
[self dismissViewControllerAnimated: YES completion: NULL];
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"What do you want to do with the user values?"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:#"Delete"
otherButtonTitles:#"Save", nil];
actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:#"Cancel"];
[actionSheet showInView:self.view];
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 2) {
NSLog(#"You have pressed the %# button", [actionSheet buttonTitleAtIndex:buttonIndex]);
}
}
On your method returnModalAction: you are dismissing the view, so the garbage collector will release all the references of self(the view controller) in memory that's why when you try to to show the action sheet [actionSheet showInView:self.view]; you get the error because the reference in memory doesn't exist.
So what you have to do is to perform [self dismissViewControllerAnimated: YES completion: NULL]; when you actually want to display the previous screen, in your case that would be on the actionSheet:clickedButtonAtIndex: method, based on the index of the button.

UIAlertview button action to change to another viewcontroller?

I am just getting into Xcode programming, and I need code so that when I click a button, it is a confirmation to take me into another ViewController.
I have an X button on the page, and when clicked I need a UIAlertview to pop up saying 'cancel' and 'next', and when next is pressed, i want it to change to another ViewController. These cancel and next buttons need to be side by side.
First thing you need to do is make sure the view with a button is a delegate of UIAlertView.
#interface ViewController() <UIAlertViewDelegate>
Then you need to add a touch up inside action to the button in your view. When the button is pressed, it creates the alertView and shows it. Note, its delegate is self.
- (IBAction)clickButton:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"Test" message: #"Message" delegate: self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Next", nil];
[alert show];
}
Lastly, you create the delegate function. This is triggered whenever a button is clicked in the alertView. buttonIndex corresponds to the button that was clicked, so we want to present the view when the 1st button is pressed (0 corresponds to cancel, 1 corresponds to next). Realistically, you'd probably want to present a custom view controller that you define.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex == 1){
UIViewController* newView = [[UIViewController alloc] init];
[self presentViewController:newView animated:YES completion:nil];
}
}

Perform UIActionSheet action's on different View Controller?

I have a slide out menu in my app, which has a button that will display a UIActionSheet. This slide out menu just partly covers whatever view controller you previously were on.
- (void)cameraButtonPushed:(UIButton *)sender
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Create String" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Take Photo", #"Choose from Library", nil];
[actionSheet showInView:[UIApplication sharedApplication].keyWindow];
//[actionSheet showInView:self.parentViewController.view];
}
As you can see I have tried two ways of showing the action sheet and they both appear to work the same.
The problem that I'm having has to do with the action sheet buttons actually working. It shows up in the parent view controller (view controller that you were on), but if I press any of the buttons they do not work.
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
EditVC *newEditVC = [self.storyboard instantiateViewControllerWithIdentifier:#"editVC"];
[editVC setHidesBottomBarWhenPushed:YES];
[self.parentViewController.navigationController pushViewController:newEditVC animated:YES];
//[self.navigationController pushViewController:newEditVC animated:YES];
} else if (buttonIndex == 1) {
EditVC *newEditVC = [self.storyboard instantiateViewControllerWithIdentifier:#"editVC"];
[editVC setHidesBottomBarWhenPushed:YES];
[self.parentViewController.navigationController pushViewController:newEditVC animated:YES];
//[self.navigationController pushViewController:newEditVC animated:YES];
}
}
Both of the above methods are in the same menu view controller where the button is pressed. I put some break points to test it out and the action sheet delegate method is being called. The if statement is working correctly, but the new VC's are not being pushed onto the navigation controller the way they should. It just runs over those lines and nothing happens. I have also tried setting it up in a way that parent view controller's also have the actionSheet:clickedButtonAtIndex: method in them, but that method is not called.
I believe that it has to do with setting up the actionSheet with an improper delegate, but I don't know for sure.
How can I call this action sheet from one view controller, display it and have actions performed in another? I have it appearing in the correct VC, but the action's aren't working.

Disabling ActionSheet dismiss on ipad when user touches outside popover

I have an actionsheet showing in my app and it all work fine on the iphone. However, on ipad it automatically creates the actionsheet within a popover and I can't get it to disable the dimissing whe the user touches outside the actionsheet.
I have changed how the actionsheet is displayed for the ipad and is now shown using:
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Choose a preloaded picture", #"Use a photo", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
actionSheet.tag = 1;
[actionSheet showFromRect:CGRectMake(100, 0, 300, 300) inView:self.view animated:YES];
[actionSheet release];
I have also tried using.
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}
Any idea on how I can stop the uiactionsheet popover from dismissing when a user touches outside the actionsheet?
Your popoverControllerShouldDismissPopover: method won't be called because it's a UIPopoverControllerDelegate method, and you're dealing with a UIActionSheet. Since the UIKit automatically creates the popover controller for you, you won't get a chance to set its delegate. You could access the popover view itself with [popoverActionsheet superview], but that won't give you the UIPopoverController.
From a user experience standpoint, Apple would ask you not to implement such behavior— if you need to present options in a modal fashion (where they don't go away until the user makes a choice) then the user will be more familiar with a UIAlertView, or a modally-presented view controller of your own.

iOS UIActionSheet presented from LongPress gesture on a button erroneously requires double clicking buttons to dismiss

I have a tabbar application, in one of the tabs I have a MKMapView. In this view, my viewDidLoad I am initializing a long press gesture recognizer for a UIButton. When this button is pressed and help it presents a UIActionSheet with 5 buttons + the cancel button. Each button represents a zoom level: "World", "Country", "State", "City", "Current Location". Selecting a button in the UIActionSheet zooms the underlying MKMapView to that level.
The problem I am having is that all of the buttons (including the cancel button) require double-tapping to dismiss the UIActionSheet. This is not the intended behavior -- it should dismiss after pressing the button once like every other UIActionSheet. After the first press I can see the map zooming to the appropriate level behind the UIActionSheet so I know the touch is registering on the correct button, but the button does not highlight blue upon the first press and the UIActionSheet does not dismiss. Not until I press the button for a second time does it highlight blue and then dismiss.
If I remove the longpress gesture recognizer and present the UIActionSheet on a 'touch up inside' then everything works as it is supposed to. So I know the gesture is somehow interfering, any ideas on a fix or workaround? Or is this a bug that should be reported to Apple?
- (void) viewDidLoad {
// intitialize longpress gesture
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(zoomOptions:)];
longPressRecognizer.minimumPressDuration = 0.5;
longPressRecognizer.numberOfTouchesRequired = 1;
[self.currentLocationButton addGestureRecognizer:longPressRecognizer];
}
- (IBAction) zoomOptions:(UIGestureRecognizer *)sender {
NSString *title = #"Zoom to:";
UIActionSheet *zoomOptionsSheet = [[UIActionSheet alloc] initWithTitle:title delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"World", #"Country", #"State", #"City", #"Current Location", nil];
[zoomOptionsSheet showFromTabBar:appDelegate.tabbarController.tabBar];
}
Anna Karenina was right, and the link provided helped me figure it out. Basically, UILongPressGestureRecognizer is a "continuous gesture" which undergoes various state changes. I needed to check for the appropriate state, which in my case is UIGestureRecognizerStateBegan since I want the UIActionSheet presented after holding the button down but before you release and stop the gesture. All I had to do was wrap the presentation of the UIActionSheet in an if statement that checked for the appropriate state. Now it works as expected.
- (IBAction) zoomOptions:(UILongPressGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan) {
NSString *title = #"Zoom to:";
UIActionSheet *zoomOptionsSheet = [[UIActionSheet alloc]
initWithTitle:title
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"World", #"Country",
#"State", #"City",
#"Current Location", nil];
[zoomOptionsSheet showFromTabBar:appDelegate.tabbarController.tabBar];
}
}

Resources