It could be probably a bug on iOS7. But the last button is not separated from the previous one
As you can see from the image. This happens on both Simulator and device using iOS7 GM.
Does everyone else has the same problem?
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:#"Title"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:#"First", #"Second", #"Third", #"Fourth", nil];
[actionSheet showInView:self.view];
As you can see the code is quite simple.
Any idea on how to fix the problem? Or some third party library I can use instead of UIActionSheet ?
I think ActionSheet requires a cancel button.So you can add the cancel button title.
Another way is: Specify actionSheet's cancelButtonIndex.
For example,in your case, you can add a "Cancel" in otherButtonTitles at index 4 and then specifiy
actionSheet.cancelButtonIndex = 4.
I found a way to make it work on iPhone and iPad in the least hacky way:
Only init the UIActionSheet with a title
Add your buttons
Add a "CANCEL" button at last
set the CancelButtonIndex to that last index
I assume that the missing separator is caused by the cancel button not being recognized as a separate case when adding it first or through the init.
I found that adding a cancel button with an empty string after initialization works. The cancel button won't show up and the separator shows up.
[sheet addButtonWithTitle: #""];
[sheet setCancelButtonIndex: sheet.numberOfButtons - 1];
But this only works for iPad. On iPhone, an empty cancel button shows up, but I found a hacky workaround to make it work. In addition to the above, in willPresentActionSheet add this code in:
NSInteger offset = 55;
CGRect superFrame = actionSheet.superview.frame;
superFrame.origin.y += offset;
[actionSheet.superview setFrame: superFrame];
// hide underlay that gets shifted with the superview
[(UIView*)[[actionSheet.superview subviews] objectAtIndex: 0] removeFromSuperview];
// create new underlay
CGRect underlayFrame = CGRectMake(0, -offset, superFrame.size.width, superFrame.size.height);
UIView* underlay = [[UIView alloc] initWithFrame: underlayFrame];
underlay.alpha = 0.0f;
[underlay setBackgroundColor: [UIColor colorWithWhite: 0.0f alpha: 0.4f]];
[actionSheet.superview insertSubview: underlay atIndex: 0];
// simulate fade in
[UIView animateWithDuration: 0.3f animations:^{
underlay.alpha = 1.0f;
}];
This shifts down the sheet to hide the cancel button off the screen
The simplest fix is to pass #"" to the cancel button title instead of nil during allocation.
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:#"Title"
delegate:self
cancelButtonTitle:#"" // change is here
destructiveButtonTitle:nil
otherButtonTitles:#"First", #"Second", #"Third", #"Fourth", nil];
[actionSheet showInView:self.view];
UIActionSheet *asAccounts = [[UIActionSheet alloc]
initWithTitle:Localized(#"select_an_account")
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles: nil];
for (int i=0; i<[result count]; i++) {
ACAccount *acct = [result objectAtIndex:i];
[asAccounts addButtonWithTitle:[acct username]];
asAccounts.tag = i;
}
[asAccounts addButtonWithTitle:Localized(#"Cancel")];
asAccounts.cancelButtonIndex = result.count;
[asAccounts showInView:self.view];
If you have a cancel button, the last row will be shown. That is the temp fix I am using now. Do not know any solution if you do not want a cancel button to show
It seems that the initWithTitle:delegate:cancelButtonTitle:destructiveButtonTitle:otherButtonTitles: method is buggy and you shouldn't specify any cancel button here at all. Btw, it seems that a destructive button set in that method also won't work very well.
Instead of it you should:
provide a custom cancel button as the last button in the buttons array, eg: ["Action 1", "Action 2", "Close"] or sheet.addButtonWithTitle("Close")
manually set the cancel button index, e.g. sheet.cancelButtonIndex = 2
Then everything will work as expected. On the iPad the button will be automatically hidden and on the iPhone it will be styled and placed in the proper way.
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
if ([UIDevice currentDevice].systemVersion.floatValue < 8.0f) {
UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(8, 88, actionSheet.frame.size.width - 16, 0.5)];
separator.backgroundColor = [UIColor colorWithRed:219.0f/255 green:219.0f/255 blue:223.0f/255 alpha:1];
[actionSheet addSubview:separator];
}
}
Every button has height 44. My actionSheet doesn't have title. And I wanted to add separator between second and third buttons. That's why I use number 88.
Related
I have a method which throws up an actionSheet which is populated by an array.
The problem is that as soon as I place that method in the sender for 1 button, it fires off for every single button press.
I only want it to display for the one button (btnPortfolio).
Here is the code for my buttons:
- (IBAction)btnPortfolio:(id)sender {
[self populatePortfolioList];
}
- (IBAction)btnAdd:(id)sender {
}
- (IBAction)btnRefresh:(id)sender {
}
and here is my method:
-(void)populatePortfolioList{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Choose your option"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
for (NSString *title in portfolio_list) {
[actionSheet addButtonWithTitle:title];
}
actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:#"Cancel"];
[actionSheet showInView:self.view];
}
since you are using IBActions, I assume that you have somehow created the methods by ctrl+dragging from the buttons into your code? is that the case? it might be possible that you accidentally connected more than one of your buttons with the method btnPortfolio which causes populatePortfolioList to be called any time the button is pressed
Hi I am facing very different kind of problem. I am using actionsheet in my iPhone application. So when I use predefine values of otherButtonTitles and if I try to change the text size then it works fine. But when I add buttons dynamically then it's not working properly.
My code looks like this:
- (void)showActions
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:cancelTitle
destructiveButtonTitle:nil
otherButtonTitles:notifications, about, faq, settings, logout, nil];
[actionSheet showInView:self.view];
}
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
for (UIView *_currentView in actionSheet.subviews) {
if ([_currentView isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)_currentView;
button.titleLabel.font = [UIFont systemFontOfSize:FONT_SIZE_16];
}
}
}
So above thing working fine. But if I try following things its not working
-(void) showCategories
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
// categoryData is string array....
for (NSString *category in categoryData) {
[actionSheet addButtonWithTitle:category];
}
actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:#"Cancel"];
[actionSheet showInView:self.view];
}
And I tried to change text size like above then its not working. Is there any reason? Need help. Thank you.
When total number of buttons exceeds height to display without
scrolling this problem occurs. (If anyone else finds the way then
please post an answer. But i think there's no answer to this !!)
On 4 inch device (640x1136 resolution), number of max buttons displayed are 11
On 3.5 inch device (640x960 resolution), number of max buttons displayed are 8.
A piece of advice:: I think if you use actionsheet this way to display more than 10 elements, Apple could reject your app. Use UIPickerView for this kind of behaviour.
I have a query that pulls the 10 nearest objects and displays the title of each in a button in a collection view. What I am trying to do is have an action that opens a new view controller displaying information of the object chosen from the collection view. What I need help with is connecting the chosen object in the buttons action. I am new to Xcode and could use some advice. This is the code defining the query:
int i = 0;
for (PFObject *object in objects) {
if (i >= [self.EventTitles count]) break;//to make sure we only write up to the max number of UILabels available in EventTitles
[(UIButton *)self.EventButtons[i] setTitle:[object objectForKey:#"name"] forState:UIControlStateNormal];
[(UIButton *)self.EventButtons[i] addTarget:self action:(social:) forControlEvents:UIControlEventTouchUpInside];
i++;
}
And then there is the code with the action
- (IBAction)social:(id)sender{
UIActionSheet *share = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Close" destructiveButtonTitle:nil otherButtonTitles:#"Call",#"Directions",#"Website",#"Checkin", nil];
[share showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
//Each button title we gave to our action sheet is given a tag starting with 0.
if (buttonIndex == 0) {
NSString* yourActualNumber = [NSString stringWithFormat:#"tel:%#",????????];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:yourActualNumber]];
NSLog(#"phone");
//Check Twitter accessibility and at least one account is setup.
}
I just do not know how to connect the object to the action, and then display that information on the new view controller.
UPDATE: I updated the code with the new line in the query, however it fails stating that the action social is undeclared however it is? I also changed the action to perform an action sheet rather than a new view controller. What I need now it a connection from the object to the action and how to write in the object for key appropriately in the action sheet function.
What I need help with is connecting the chosen object in the buttons
action.
[button addTarget:self action:#selector(DetailEvent1:) forControlEvents:UIControlEventTouchUpInside]
and then display that information on the new view controller.
I don't really know what you are asking here, if you clarify I'll try my best to help :)
Here is an example where an action sheet is displayed when an item is selected. I'm simply using the index path of the selected item, but I assume you have some other data you'd need to save so the Action Sheet delegate can use it.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSString *str = [NSString stringWithFormat:#"Call number %d", indexPath.row];
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:(id < UIActionSheetDelegate >)self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:str, nil];
[actionSheet showInView:self.view];
}
In my Phone App I need an ActionSheet where I have multiple button sections and the possibility to select one button of each section. An accept the whole with an Ok button.
First I have a method where I open the ActionSheet:
-(void)showActionSheet{
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles: nil];
for(int i = 0; i < [selectionArray count]; i++){
ObjektGroup *groupArray = [selectionArray objectAtIndex:i];
for(int j = 0; j < [groupArray count]; j++){
[sheet addButtonWithTitle:nameofbuttonbla];
}
[sheet addButtonWithTitle:#"------------------"];
}
[sheet addButtonWithTitle:#"OK"];
sheet.cancelButtonIndex = sheet.numberOfButtons-1;
[sheet showInView:self.view];
}
As you can see, I add the Buttons dynamicly. That works fine, but the section devider ([sheet addButtonWithTitle:#"------------------"];) is not the final solution that I want.
So is there a possibility to devide the groups like a grouped tableView?
+ I want only select one Button per section.
Another Problem is when following Method gets called:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{}
The Actionsheet dismisses automaticly. I want to avoid that too.
Any ideas?
You cannot do this with a UIActionSheet unfortunately as it only allows you to have one section and particularly it is meant to be dismissed after a single click.
As Apple doesn't allow UIActionSheet subclassing, you should look into building a customised solution using a UITableView.
I created a custom action sheet which has the ability of displaying multiple sections and you can completely customize the buttons or display your custom content view! You will be able to configure multiple selection! Have fun: https://github.com/JonasGessner/JGActionSheet
I have encountered something like this before, where a button only responds to touches in part of its view. I found a image view with a transparent area was on a higher z-level, which obscured the touches where the overlap occurred. This was due to the button being added as a subview before the obscuring view was added.
In the case of an action sheet, I thought it would be at the highest z-level over anything else. Since the action sheet was just initialized and shown, there is no way that I can see that something is covering the button.
(For what it's worth, I just converted the app into a universal app, and am testing in both iOS 4.3 and 5.0. There is no cancel button in the action sheet on the iPad. This problem exists when simulating for iPhone for both iOS 4.3 and 5.0.)
I'm looking for other ideas as to what is causing the problem.
UPDATE
Here is the code to show the action sheet
- (void) shareButtonPressed {
SHKItem *item = [SHKItem larkspreeSearchResult:searchResult];
item.image = eventImageRaw;
// Get the ShareKit action sheet
SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item];
// Display the action sheet
[actionSheet showInView:self.view];
}
Since this is for a subclassed action sheet, this, right out of ShareKit, might be helpful, too.
+ (SHKActionSheet *)actionSheetForType:(SHKShareType)type
{
SHKActionSheet *as = [[SHKActionSheet alloc] initWithTitle:SHKLocalizedString(#"Share")
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
as.item = [[[SHKItem alloc] init] autorelease];
as.item.shareType = type;
as.sharers = [NSMutableArray arrayWithCapacity:0];
NSArray *favoriteSharers = [SHK favoriteSharersForType:type];
// Add buttons for each favorite sharer
id class;
for(NSString *sharerId in favoriteSharers)
{
class = NSClassFromString(sharerId);
if ([class canShare])
{
[as addButtonWithTitle: [class sharerTitle] ];
[as.sharers addObject:sharerId];
}
}
// Add More button
[as addButtonWithTitle:SHKLocalizedString(#"More...")];
// Add Cancel button
[as addButtonWithTitle:SHKLocalizedString(#"Cancel")];
as.cancelButtonIndex = as.numberOfButtons -1;
return [as autorelease];
}
The showInView method has not been overridden.
If this view controller is part of a UINavigationController with a toolbar configured or a UITabBarController then any action sheet needs to be presented in the parent controller's view. For instance, [actionSheet showInView:self.navigationController.view]; or [actionSheet showInView:self.tabBarController.view];.