Strange behavior of Cancel button's ActionSheet - objective-c

I'm new in Objective-C, I try to code an iPad App (Objective-C 2.0, Xcode 4.0.1).
I "play" with ActionSheet to understand how it works. In a nib file I put a button binded to my "buttonPressed" method.
I've written this code :
-(IBAction)buttonPressed
{
UIActionSheet *myActionSheet = [[UIActionSheet alloc] initWithTitle:#"My Action Sheet" delegate:nil cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"OK" otherButtonTitles:#"Test", nil];
NSLog([NSString stringWithFormat:#"%d", [myActionSheet numberOfButtons]]);
NSLog([myActionSheet buttonTitleAtIndex:0]);
NSLog([myActionSheet buttonTitleAtIndex:1]);
NSLog([myActionSheet buttonTitleAtIndex:2]);
[myActionSheet showInView:self.view];
[myActionSheet release];
}
This is the NSLog result :
2011-04-14 14:52:30.428 TrampManage[3568:207] 3
2011-04-14 14:52:30.429 TrampManage[3568:207] OK
2011-04-14 14:52:30.430 TrampManage[3568:207] Test
2011-04-14 14:52:30.432 TrampManage[3568:207] Cancel
But the displayed view is quiet different (cf image : http://www.imagup.com/data/1117452257.html). For the moment, I've one simple question : Why my "Cancel" button doesn't appear ?

As your tag hints, you are probably working on an ipad project.
The documentation says about the cancel button for iPads:
cancelButtonTitle The title of the
cancel button. This button is added to
the action sheet automatically and
assigned an appropriate index, which
is available from the
cancelButtonIndex property. This
button is displayed in black to
indicate that it represents the cancel
action. Specify nil if you do not want
a cancel button or are presenting the
action sheet on an iPad.
You can cancel by touching outside the action sheet.

You're most likely on an iPad, where the new interface idiom is to not show the cancel button. A user can cancel the sheet by simply clicking outside the sheet. Not the best design decision IMHO, but that's the way it is now.

on ipad it doesn't shows the cancel button. because ipad has more width than the iphone & for dismiss it you can tab outside the actionsheet on ipad.
Detail explaination:
see this image of iphone which shows ok button
below Figure shows the action sheet when displayed on the iPad.
Interestingly, on the iPad the OK button (set by the
cancelButtonTitle: parameter) is not displayed.
The value (buttonIndex) of each button when clicked is as follows: ➤
Delete Message — 0 ➤ Option 1 — 1 ➤ Option 2 — 2 ➤ OK
— 3 On the iPad, when the user taps on an area outside of the
action sheet, the action sheet is dismissed and the value of
buttonIndex becomes 3. Interestingly, if you specified nil for the
cancelButtonTitle: part, the value of buttonIndex would be –1 when the
action sheet is dismissed.

Related

UIActionSheet in iOS7 dismissing when user taps ANYWHERE on the screen on iPhone

I've noticed that in iOS 7 a **UIActionSheet** automatically dismisses when a user taps anywhere on the screen on an **iPhone**. This was NOT the case in iOS 6 and is leading to unintended effects. Is this a UI change? Bug? Is there a way to disable this?
From iOS 7 docs: "As described in iOS human interface
guidelines, you should include a Cancel button with action sheets
displayed on iPhone and with those displayed on iPad over an open
popover. Otherwise on iPad, action sheets are displayed within a
popover, and the user can cancel the action sheet by tapping outside
the popover, in which case you do not need to include a Cancel
button."
This seems to suggest that the behavior of dismissing when tapping anywhere outside the action sheet should only pertain to iPads. But this is now happening on an iPhone running iOS 7 when it doesn't on an iPhone running iOS 6
Regarding your question Is this a UI change? Bug?
It is seems like an UI change not a bug how can I say that ? Have a look at the image i took from iOS7 simulator
It is a image of Maps application of iPhone.
When you click on button ( display in red rectangle ) one action sheet will display which have Cancel button like below
And if you click any where else it will close, same behaviour also found in other Apple applications also like safari.
Regarding your question Is there a way to disable this?
Sorry but i don't have answer for that.
A word before I post my solution. It is very easy to fear a minor change in behavior and to want to disable it right away. But consider first consistency. This is how action sheets behave across the operating system. If you disable this behavior, you will break consistency and this will result in a subpar experience for your users.
That said, here is my solution.
UIActionSheet on iPhone opens its view in a separate UIWindow instance which becomes key when it is shown. You can access this window using [UIApplication sharedApplication].keyWindow. If you inspect the view hierarchy of this window, you will notice several private classes such as dimming view. You can recursively traverse this view hierarchy and set view.userInteractionEnabled = NO; to every view there that is not a subclass of UIButton. This should do the trick.
As #nvrtdfrst implies in his comments, setting cancelButton: nil will get rid of the default dismissal behavior. But you can still have a cancel button by setting the text for one of the custom buttons to #"Cancel"--to be treated by the delegate method, something like this:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:#"Cancel"]) {
// your cancellation code here
}
}
A bit hacky, but that's a simple solution.
H/T: null.
Use
- (void)actionSheet:(UIActionSheet *)actionSheet
didDismissWithButtonIndex:(NSInteger)buttonIndex {...}
This worked for me.
(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self performSegueWithIdentifier:#"firstOption" sender:self];
}else if (buttonIndex == 1){
[self performSegueWithIdentifier:#"secondOption" sender:self];
} else if (buttonIndex != 0 || buttonIndex != 1) {
[actionSheet cancelButtonIndex];
}
}

Displaying an action sheet over a disabled tab bar in tab bar partially enables it

I think I found a bug in UIKit, but first I want to be sure I'm not insane.
I have a tab bar with a disabled tabBarItem in it. If I present an action sheet from the tab bar, then cancel/press any button in it, after the action sheet dismisses the tab bar item appears enabled, but cannot be clicked.
I want it to stay disabled.
I uploaded an example project here. Run it in the simulator and press the action sheet button on the first view controller. Note the state of the second tab bar item before and after the sheet appears. The project itself is a standard "Tabbed Application" template with one tab item disabled and an IBAction for the button added.
Is this a bug, or am I misusing the APIs?
Looks like a bug it is...
As a quick and safe workaround add this to the view controller (assuming it will be an UIActionSheet's delegate)
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
for (UITabBarItem *item in self.tabBarController.tabBar.items) {
item.enabled = !item.enabled;
item.enabled = !item.enabled;
}
}
I have checked your Project and found a way to make it work. But I don't know actually is it a bug or not. I just find out, it is happening only when you show the actionsheet from the method using showFromTabbar: method.
[sheet showFromTabBar:self.tabBarController.tabBar];
When i changed it to show in this view only, then its not changing the tabBarItem image.
[sheet showInView:self.view];
Hope this could help you to continue to work on that project.

UISearchBar in UINavigationController with cancel button not selectable

I have added a UISearchBar to the UINavigationController just fine, but as soon as I add the cancel button to the search bar I can no longer select it by touching it.
The code I'm using to create the search bar and add it is:
UISearchBar *theSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0f,0.0f,320.0f,0.0f)];
theSearchBar.delegate = self;
[theSearchBar setPlaceholder:#"Search iPad"];
[theSearchBar setShowsCancelButton:YES animated:YES];
self.navigationItem.titleView = theSearchBar;
self.navigationItem.titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[theSearchBar release];
If I remove the line to add the cancel button I'm able to focus on the search bar and the search works correctly. As soon as I put that line in, it displays properly, but I can no longer focus on it.
I've tried putting it into a simple UIView container, but that didn't solve the problem either.
What about adding the cancel button could be causing this to fail?
UPDATE:
I ended up not using the cancel button because I determined it wasn't necessary the way the search bar was being used.
I would definitely recommend a UISearchDisplayController: apple docs.
It has a cancel button built right in, and by placing it in interface builder you can save a lot of code. Less code = less bugs.

What's going on with my UIButtons in a xib?

I have a set of UIButtons (defined in a xib) who have labels that need to be updated periodically. In the ViewDidLoad method of the view controller of those buttons' superview, I have an update method that does, for each button:
button.titleLabel.text = #"Relevant Text";
[button setNeedsDisplay];
and when you tap a button, another method runs which pops up a UIAlertView, which in turn calls back a method on the view controller which does much the same thing as the initial text setting method:
button.titleLabel.text = #"New Text";
[button setNeedsDisplay];
however, this code simply isn't working, the button label's text doesn't get updated in either method, it remains a blank white button. In the xib I don't define any text on the buttons - there's no point, the button text doesn't make sense unless it's set at runtime. Anyway, on a lark, I decided to set the text of one of the buttons to "test test test".
Now, when I tap that particular button, it pops up the UIAlertView but in the background changes the text of the button to "test test test test". And this time, the UIAlertView callback does what I expect it to and sets the text for only that button. When I hit it again, the text goes back to "test test test test" until I dismiss the UIAlertView, which again will run the callback method and set the button text to whatever the method should.
I have no idea what's going on here, or why setting the text initially in the xib has any relation to whether or not I can set that text later programatically. Obviously this isn't the behavior I want, I want to know how to for sure set the text on the buttons.
Edit: SVD's advice about setTitle:ForState: solved my problem, thanks. I'm still curious though as to why the title label set in the .xib shows up, but only when I have a UIAlertView pop up.
You may need to use [setTitle: forState:] to set the button title for normal and highlighted (or selected) state.
(And do make sure the button is connected to the outlet, as jtbandes points out).

What's going on with my UIButtons in a xib? [duplicate]

I have a set of UIButtons (defined in a xib) who have labels that need to be updated periodically. In the ViewDidLoad method of the view controller of those buttons' superview, I have an update method that does, for each button:
button.titleLabel.text = #"Relevant Text";
[button setNeedsDisplay];
and when you tap a button, another method runs which pops up a UIAlertView, which in turn calls back a method on the view controller which does much the same thing as the initial text setting method:
button.titleLabel.text = #"New Text";
[button setNeedsDisplay];
however, this code simply isn't working, the button label's text doesn't get updated in either method, it remains a blank white button. In the xib I don't define any text on the buttons - there's no point, the button text doesn't make sense unless it's set at runtime. Anyway, on a lark, I decided to set the text of one of the buttons to "test test test".
Now, when I tap that particular button, it pops up the UIAlertView but in the background changes the text of the button to "test test test test". And this time, the UIAlertView callback does what I expect it to and sets the text for only that button. When I hit it again, the text goes back to "test test test test" until I dismiss the UIAlertView, which again will run the callback method and set the button text to whatever the method should.
I have no idea what's going on here, or why setting the text initially in the xib has any relation to whether or not I can set that text later programatically. Obviously this isn't the behavior I want, I want to know how to for sure set the text on the buttons.
Edit: SVD's advice about setTitle:ForState: solved my problem, thanks. I'm still curious though as to why the title label set in the .xib shows up, but only when I have a UIAlertView pop up.
You may need to use [setTitle: forState:] to set the button title for normal and highlighted (or selected) state.
(And do make sure the button is connected to the outlet, as jtbandes points out).