Why is my UIActionSheet hidden by my TabBarController? - objective-c

I am having a problem correctly implementing a UIActionSheet in an iPad 5.1 (XCode 4.3) project. I can populate it correctly with all the items I need. The list is longer than the window, but the scrollbars automatically come up, etc. However, the cancel button (which I presume is supposed to be at the end) is coming up half hidden behind my tab bar. Shown below:
(sorry, SO won't let me post images yet)
Here is my storyboard setup:
The entry point is that Tab Bar Controller on the left, which goes to another Navigation Controller (center), which has the View Controller on the right as the root view.
http://i854.photobucket.com/albums/ab103/srVincentVega/ScreenShot2012-06-28at52713PM.png
I have tried presenting the UIActionSheet in all sorts of ways, but this odd behavior persists, and I can't figure out how to address it
- (IBAction)cmdReason:(id)sender
{
NSArray *reasons = [AppState getInspReasons];
UIActionSheet *action = [[UIActionSheet alloc]
initWithTitle:#"Reason for Inspection"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:nil];
for (NSString *rsn in reasons)
{
[action addButtonWithTitle:rsn];
}
[action showInView:self.view];
}
I have tried the various methods to show "action" - showFromTabBar, showFromToolbar, etc - I am VERY new to this development environment, so I am not up to speed yet on how these items interact at this level. Does anyone have a suggestion for how I can present this correctly?
I am sorry if this has already been asked elsewhere. I have spent all day trying bits of code from all over the web, including SO. I don't know if it's something to do with my storyboard layout, or what.
One further thing - when I rotate the emulator, the action sheet does redraw, but the bit at the end there gets wonky looking, like it can no longer figure out how to draw it.
Many thanks!
EDIT:
I have put together a very small project that demonstrates this exact behavior. I don't have a good way to host the zip file, so I put on google docs and shared it. The link is below. If you click on that, there should be a download option under file that will give you the original zip file.
https://docs.google.com/open?id=0B7IYvy9_c_NLaEFneGc5bzc2S2c

Seems like there is not a real solution for this. It looks like it's a limitation with UIActionSheet if you add that amount of button titles and present that from a tab bar.
Beside that, the proper way to display an UIActionSheet from a tab bar is to use
[action showFromTabBar:self.tabBarController.tabBar];
instead of
// Taken from your example project
AppDelegate *d = [[UIApplication sharedApplication] delegate];
UIWindow *w = d.window;
UIViewController *vc = w.rootViewController;
UITabBarController *c = (UITabBarController *)vc;
UITabBar *t = c.tabBar;
[action showFromTabBar:t];

I would think if you got a reference to the tab bar controller then you should be able to present it from that. You can try showing it from the main window but I would think you shouldn't rely on that.
[action showInView:[[UIApplication sharedApplication] keyWindow]];

Try this:
CGRect r = CGRectMake(x, y, w, h); //change values to fit location of button
[actionSheet showFromRect:r inView:self.view animated:YES];
I used it on one of my apps with the same problem and the dismiss button showed up ok.

Related

NSButtons Inside NSPopover View Controller

I've developed for Mac before but this is the first time I've attempted to use the NSPopover control, which seemed like a great idea to start out with but so far is causing me no end of problems. The applciation is a menu bar application. I have two NSButton objects in the NSPopover's view controller, the NSPopover is being created programmatically in another subclass of NSButton, the same button which it is being shown relative to. This NSButton that it is being shown relative to is contained along with some other buttons in an NSMenuItem
The popup, containing the two buttons, is being shown fine (see screenshot below), however, despite the 'Yes' button being highlighted with a focus ring, neither button responds to click events, they do not even graphically click in like I would expect them to.
And this is the code that creates the NSPopover and positions it onscreen:
someViewController *confirmationDialogue = [[someViewController alloc] initWithNibName:#"someViewController" bundle:nil];
popOver = [[NSPopover alloc] init];
[popOver setBehavior:NSPopoverAppearanceMinimal];
[popOver setBehavior:NSPopoverBehaviorTransient];
[popOver setContentViewController:confirmationDialogue];
[popOver showRelativeToRect:NSMakeRect(0, 0, self.frame.size.width, self.frame.size.height))
ofView:self
preferredEdge:NSMaxYEdge];
Has anyone got any kind of solution/workaround to this?
Thanks in advance :)
P.s. This is my first question on SO, so I hope I've provided enough information but I'll give any more details as needed.

How to make UIActionsheet recognize which button was most recently pushed?

I'm currently implementing a UIActionsheet that has two buttons.
Each of the buttons save different values into [NSUserDefaults standardUserDefaults]
The implementation i have atm:
-(void)foo{
UIActionSheet *mySheet = [[UIActionSheet alloc] initWithBlabla:blabla];
[mySheet showFromTabBar:myTabBar];
[mySheet release];
{
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex == x){
[[NSUserDefaults standardUserDefaults] setValue:foo forKey:bar];
{
else{
// bla
{
}
Now, for the issue i'm having at hand.
I would really like the actionsheet to recognize which of the buttons that was clicked most recently and present that in some way.
So for example, the first time the actionsheet shows, both buttons are gray as default, one button gets pressed and the actionsheet goes away.
The second time the actionsheet shows, it shows up just as the first time. And i'ld like the actionsheet to give the user feedback regarding which of the buttons was most recently pushed. (a different coloring or anything really).
If i could acces the buttons generated within the actionsheet this would be a no-problemo.
In pseudo-code i'd probably want kind of solution as below
UIActionSheet *myActionSheet = [[UIActionSheet] alloc] initwithBlabla:blabla];
if([[userDefaults objectForKey:#"foo"]isEqualToString:#"bar"])
{
[myActionSheet setHighLighted:otherButton2];
}
I would like the actionsheet to recognize what the userdefaults for the key foo is and make adjustments to the buttons within the UIActionSheet.
Any tips and/or pointers on how to implement such a thingie will be highly appreciated!
A UIActionSheet has three distinct button display styles: A destructive button ( Red ) for.. well, destructive actions, a cancel button, which is the bottom one and slightly darker than the regular buttons, and the so-called "other buttons", which are color gray.
Now, if you want to go with a no-hacky-hacky solution, you can use those three colors to create the effect you need, by simply creating a if-condition and instantiating your actionsheet a bit differently every time.
If you are all into hacky-hacky solutions and want some more colors, you might want to consider iterating over all subviews in the actionsheet and modify their style directly. But be warned: your solution might not work in future releases of iOS since there is no guarantee that internal components without a public API won't change ( That's why there is no public API for it in most cases ).

UIDocumentInteractionController: "Open In" visible on iPhone but not on iPad - why?

For testing purposes I wrote two apps:
First one plays an MP3 file using UIDocumentInteractionController
Second one does nothing but registers for the file type "public.mp3"
If I deploy the apps to the iPhone Simulator, my MP3 player app shows a button on top "Open in 'MP3Test'". If I deploy to the iPad Simulator however, there is no button and no "Open In" menu either.
This has been tested with iOS5.
Can somebody explain if this is a bug or a feature and what the reason is behind it?
Depends upon where you are presenting it from.
If you are presenting it from somewhere around the middle of the screen or below, just present from the frame of the object that you are presenting from.
if that is on the navigation bar, try this:
NSString *fileToOpen = [[NSBundle mainBundle] pathForResource:#"License" ofType:#"pdf"];
UIDocumentInteractionController *controller = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:fileToOpen]];
controller.delegate = self;
CGRect navRect = self.navigationController.navigationBar.frame;
navRect.size = CGSizeMake(1500.0f, 40.0f);
[controller presentOptionsMenuFromRect:navRect inView:self.view animated:YES];
The iPad has an affinity for popovers (see UIPopover), why it presents UIActionSheets in them. Facing a similar issue that you had, I had my UIDocumentInteractionController present itself from an UIBarButtonItem (resulting in a UIPopover presentation), rather than from the view itself (something that worked just fine on the iPhone):
Save a reference to the action button (I have mine in my navigation bar).
Use PresentOpenInMenu using the action button reference, rather than the View reference, resulting in a UIPopover-presentation.
Please note that the change does not effect the iPhone app - it behaves likes before, i.e. opens the OpenInMenu from the bottom of the screen just as it would, if you'd used the View reference to present it.
On iPad UIDocumentInteractionController appearing like Pop Up Try something like this
-(void)shareClick:(UIButton*)sender {
/*some code*/
CGRect rectFor appearing = [sender.superview convertRect:sender.frame toView:self.view];
[interactionController presentOptionsMenuFromRect:rect inView:self.view animated:YES];
}

Loading another view from table selection without losing navigation (back)

I have an app that is controled through a UITabBar. In one of the sections within the tab bar, I have a navigation table. It works fine from an example I did from one of the books but I want to be able to go another view controller (aka another xib file) when the user selects a row and I want the user to be able to go back easily. I realize this has to do with pushingViewControllers but I am stuck. Here is where I think the problem is. my code is at the bottom. If you notice, I commented out
// [self presentModalViewController:flowerDetailViewController animated:YES];
While this did take me to the my flowerDetailViewController XIB file, I lost the ability to do navigation (go back). If anyone has any ideas or suggestions, it would be much appreciated.
Thank you
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
FlowerDetailViewController *flowerDetailViewController =
[[FlowerDetailViewController alloc] initWithNibName:
#"FlowerDetailViewController" bundle:nil];
/*flowerDetailViewController.detailURL=
[[NSURL alloc] initWithString:
[[[flowerData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:#"url"]];*/
flowerDetailViewController.title=
[[[flowerData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:#"name"];
//[self presentModalViewController:flowerDetailViewController animated:YES];
[self.navigationController pushViewController:
flowerDetailViewController animated:YES];
[flowerDetailViewController release];
}
It doesn't make any sense to execute these two methods on the same view consecutively.
[self presentModalViewController:flowerDetailViewController animated:YES];
..
[self.navigationController pushViewController: flowerDetailViewController animated:YES];
because they give a very different result, from user experience point of view.
The first one presents a view modaly. Modaly means, that he application brings up the view to the top (imagine a Z-axis, when you hold the phone, it is a line from the phone to you, on top of it means closer to you), and the user is stuck in that view exclusively because it is on the top, he/she cannot touch anything else from the application unless he resolves the options presented in the view and the view goes away.
The second method is pushing the view onto he stack of views that all belong to the navigation controller. The navigation controller pushes views onto the screen like you would lay a stack of cards onto the table, card1, put onto that card 2, put onto that card 3...and so on card N. But you still have the ability to touch other options that are all around the navigation controller.To get back to the card 1, you need to remove card(views) that are on top of it, for removing on-top views, the navigation controller provides the back button automatically.
Only you cann tell, which of these two is handy in terms of your application UI and design.

Create UINavigationController programmatically

Just because I am unable to find a secure way (in a sense that it can be rejected by Apple guys) to customize UITabbar, in particular UITabBarItem I am trying some workaround.
I have a main view on which I recreate a kind of UITabBar, a normal view with two buttons inside. This is (roughly) the current hierarchy:
-MainView
--placeholder(UIView)
--fakeTab (UIView)
What I want to do is, after tapping a button in fakeTab, build a UINavigationController and add it to "placeholder" view so that the fakeTab remain on top and the whole navigation happens on the placeholder level.
I already tried with this piece of code in the method that it's intercepting tap button, and it works, I can see the ipvc.view added to placeholder.
IPPlantsViewController *ipvc = [[IPPlantsViewController alloc] initWithNibName:#"IPPlantsView" bundle:[NSBundle mainBundle]];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:ipvc];
UIView *placeholder = [self.view viewWithTag:200];
[placeholder addSubview:ipvc.view];
But later when I call from inside ipvc, then nothing happens:
IPAttributes *ipas = [[IPFactory findPlantByIndex:indexPath.row] attrs];
[self.navigationController pushViewController:ipa animated:YES];
I find the solution myself. What I was doing wrong is to attach the ipvc controller view to placeholder. Instead of doing this:
[placeholder addSubview:nav.view];
and everything works as expected, with my fake tabbar fully customized :-)
But, as a side note, the viewWillAppear seems to be never called.
It would be interesting to know why. I partially solved by making IPPlantsViewController the delegate of the UINavigationController.