I'm adding a series of buttons to a UINavigationBar using:
NSArray *items;
items = [NSArray arrayWithObjects:
fixedSpace,
refreshStopBarButtonItem,
flexibleSpace,
self.backBarButtonItem,
flexibleSpace,
self.forwardBarButtonItem,
flexibleSpace,
self.actionBarButtonItem,
fixedSpace,
nil];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, toolbarWidth, 44.0f)];
toolbar.items = items;
toolbar.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:1.0];
toolbar.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:toolbar];
All working well.
However when I rotate to landscape mode the toolbar within the uinavigationbar doesn't rotate.
Adding this code (found on SO) causes the toolbar to resize but not the buttons within it, so they are partially cropped at the bottom and no longer lines up with the toolbar background
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
CGRect navigationToolbarFrame = self.navigationController.navigationBar.frame;
CGRect customToolbarFrame = CGRectOffset(navigationToolbarFrame, 0.0, navigationToolbarFrame.size.height);
[UIView animateWithDuration:duration animations:^{
//self.toolbar.frame = customToolbarFrame;
// FAILS!!!
//self.navigationItem.rightBarButtonItem.toolbar.frame = customToolbarFrame;
// FAILS!!!
}];
}
What is the correct way to address the toolbar within the uinavigationbar?
Something like...
self.toolbar.frame = customToolbarFrame;
Or do I have to specify a autoresizemask for the UIBarButtonItems?...
self.backBarButtonItem.autoresizingMask = UIViewAutoresizingFlexibleHeight;
... trying to do so like this fails
Very curious because this code rotates toolbar fine when I include it in my code. No problem rotating the toolbar.
I assume your view controller is responding to shouldAutorotateToInterfaceOrientation? Could you include screen snapshot of what you're seeing?
Are you doing any UIToolbar category/subclass to eliminate its border? (I just subclass with empty (void)drawRect:(CGRect)rect to get rid of border, but I tried both that and the standard UIToolbar and both rotated fine.) Anyway, if you're doing subclass/category of UIToolbar, please include that code?
Also, you could alternatively just use iOS 5's rightBarButtonItems and bypass the toolbar altogether, e.g. self.navigationItem.rightBarButtonItems = items; will then add the array of UIBarButtonItem objects to the navigation bar.
This is a bit of a long shot, but how is your view controller being loaded? Some people try bypassing presentViewControllerAnimated and/or pushViewController and instead simply create a view controller, grab its view, add it as a subview of the previous view controller's view. Unfortunately, this ends up with a disconnect between the view controller hierarchy and the view hierarchy, and according to WWDC 2011 session 102 on view controller containment, this can prevent rotation events from being transmitted correctly. Make sure you're using presentViewControllerAnimated or pushViewController if this isn't your root view controller.
I don't do any of that willAnimateRotationToInterfaceOrientation or subsequent code, just the simple UIToolbar and it works fine during rotation, so I wonder if the problem rests elsewhere.
Related
I have a view controller that contains a UITableView. I'm trying to put the UITableView into a UITabBarController as one of the views. It wont work, nothing will show up on the bottom. If I put an iAd banner on the bottom, it doesn't show. The UITabBar will not show. I don't know what the problem is. I'm figuring that maybe the UITableView is going somehow over the UITabBar, but I really have no clue. I tried making it shorter, but to no avail. Any help would be much appreciated. Also, I'm doing this using UIStoryboards, mainly. I'm not sure what code is relevant here, so please just tell me if you need to see any. Thanks in advance,
-Sam
I went through what you're going through - I'm also using storyboards. I don't remember where I found this snippet but it has worked well for me. Credit should go to the guy who wrote it originally.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//Initialize the toolbar
toolbar = [[UIToolbar alloc] init];
toolbar.barStyle = UIBarStyleDefault;
//Set the toolbar to fit the width of the app.
[toolbar sizeToFit];
//Caclulate the height of the toolbar CGFloat
CGFloat toolbarHeight = [toolbar frame].size.height;
//Get the bounds of the parent view
CGRect rootViewBounds = self.parentViewController.view.bounds;
//Get the height of the parent view.
CGFloat rootViewHeight = CGRectGetHeight(rootViewBounds);
//Get the width of the parent view,
CGFloat rootViewWidth = CGRectGetWidth(rootViewBounds);
//Create a rectangle for the toolbar
CGRect rectArea = CGRectMake(0, rootViewHeight - toolbarHeight, rootViewWidth, toolbarHeight);
//Reposition and resize the receiver
[toolbar setFrame:rectArea];
// add buttons (make sure you create your buttons)
//[toolbar setItems:[NSArray arrayWithObjects:trashButtonItem, leftSpaceButtonItem, cameraButtonItem, rightSpaceButtonItem, addButtonItem, nil]];
//Add the toolbar as a subview to the navigation controller.
[self.navigationController.view addSubview:toolbar];
}
You'll have to substitute the buttons with your own obviously.
You need to extend your class by UIViewController, not UITableViewController because that takes up your entire view.
I am trying to add a the UINavigationController UIToolbar to the top of the view, (under the navigation controller.
My view is a UITableViewController... so there is that to deal with. Currently I am just positioning the UIToolbar that appears at the bottom of the view where I want it to display using
[self.navigationController.toolbar setFrame:CGRectMake(0, 60, 320, 30)];
this positions the toolbar in the correct place I would like it to appear, However there is a problem with where its positioned, which I will explain.
When you set a UINavigationController toolbar to be displayed it puts itself at the bottom of the view and pushes the UITableView up so the toolbar does not cover the tableview. However when I change the position of the toolbar the tableview still thinks the toolbar is at the bottom of the screen meaning the toolbar does not meet flush at the bottom of the screen how I would like it too.
So my question is how can I get the toolbar to display directly below the navigation controller bar and push the tableview down abit to accommodate for the toolbar in its new position.
I hope this all makes sense, Any help I would like to than in advance and below is the current code I am using (all be it basic I am still abit perplexed about whats going on behind the scenes for this to happen).
- (void) viewDidLoad
{
//..
[self.navigationController setToolbarHidden:NO animated:YES];
[self.navigationController.toolbar setFrame:CGRectMake(0, 60, 320, 30)];
self.navigationController.toolbar.tintColor = [UIColor lightGrayColor];
//..
}
update
this is currently what the toolbar is doing to my tableview
Call setFrame on your UITableView to move it into positon.
float y = self.navigationController.toolbar.frame.origin.y + self.navigationController.toolbar.frame.size.height;
[myTable setFrame:CGRectMake(0, y, self.view.frame.size.width, self.view.frame.size.height-y)];
i have a UIView that is smaller than the superview so i can represent this view as a modal view when a button is clicked.
I have managed to do the following:
* add a subview to the superview.
* centered this modal view
I am now trying to make the elements behind the UIView unclickable. And also add a grey shadow te the ourside of my modal view so that the user understands that the modal view is the view in focus.
I would like to know how to achieve this.
I do not wish to use the presentation modal transition. I know and have already implemented this in other projects.
Any help is appreciated.
The simplest thing would be to lay a fullscreen UIView with a translucent gray background behind your "modal" view. Then it will intercept all of the touches. It might look something like this:
UIView *dimBackgroundView = [[UIView alloc] initWithFrame:theSuperview.bounds];
dimBackgroundView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:.5f];
[theSuperview addSubview:dimBackgroundView];
[theSuperview addSubview:modalView];
For future reference, you can set myView.userInteractionEnabled = NO to disable touch events on a view.
There are several ways to do it.
If you have a custom view which has custom location, you can modify it like that:
Create an instance var:
UIView* backgroundView;
And whenever you need it, put it behind your custom view:
if (backgroundView == nil)
backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width)];
backgroundView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:.5f];
[self.view addSubview:backgroundView];
[backgroundView animateBump:customView.view];
[backgroundView addSubview:customView.view];
When you do not need it anymore
[backgroundView removeFromSuperview];
I have an issue with a UINavigationBar and its y-offset. The bar is displayed without a UINavigationController as superview, yet that should not matter. In the viewController where the navigation bar appears the setup looks like this:
// Add Basic View
CGRect viewFrame = [[UIScreen mainScreen] applicationFrame];
UIView *myView = [[UIView alloc] initWithFrame:viewFrame];
myView.backgroundColor = [UIColor greenColor];
self.view = myView;
[myView release];
UINavigationBar *myBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
.... add some Stuff to the bar...
[self.view addSubview:myBar];
[myBar release];
As I add the navigationBar as a chield View to self.view I assumed that origin.y = 0 would mean that the bar should get directly displayed below the status bar. This works as expected if I start the app on my iPad, rotate it once (or more) and then drill down to the view that is described above. In this case the UINavigationBar is displayed properly. Yet if I start my app and directly drill down to the controller described above (without rotating the device before this particular controller appears) the navigation bar slides 20 points below the status bar. But as soon as I rotate the device then, the bar is fine again. I have checked the viewFrame.origin.y value and it is 20 points in both situations, hence I do not understand why in one case the bar just seems to ignore the origin.y value of its superview but does not in the other.
I am really confused about this, has anybody else ever experienced such an issue?
Thanks a lot for your help!
Ps. I have also tried it with a UIToolbar, the problem is the same.
Yes. My solution is to set the "Full screen on launch" flag to on in Interface Builder for the window in the MainWindow-iPad.xib file. Then design your views as if the 20 pixel status bar were always displayed, so in my root view, I have a toolbar that is positioned 20px below the top of the screen in the content view.
I'm trying to do something that shouldn't be that complicated, but I can't figure it out.
I have a UIViewController displaying a UITableView. I want to present a context menu when the user press on a row. I want this to be a semi-transparent view with labels and buttons.
I could use an AlertView, but I want full control on the format of the labels and buttons and will like to use Interface Builder.
So I created my small view 250x290, set the alpha to .75 and create a view controller with the outlets to handle the different user events.
Now I want to present it.
If I use presentModalViewController two (undesired) things happen
1) the view covers all of the screen (but the status bar).
2) It is semi-transparent, but what I see "behind" it its not the parent view but the applications root view.
Ive tried adding it as a subview, but nothing happens, so Im not doing something right:
RestaurantContextVC* modalViewController = [[[RestaurantContextVC alloc] initWithNibName:#"RestaurantContextView" bundle:nil] autorelease];
[self.view addSubview:modalViewController.view];
Is it possible to do what I want?
Thanks in advance.
Gonso
I'm coding similar thing. My approach include.....
Not using dismissModalViewControllerAnimated and presentModalViewController:animated.
Design a customized full sized view in IB. In its viewDidLoad message body, set the background color to clearColor, so that space on the view not covered by controllers are transparent.
I put a UIImageView under the controllers of the floating view. The UIImageView contains a photoshoped image, which has rounded corners and the background is set to transparent. This image view serves as the container.
I uses CoreAnimation to present/dismiss the floating view in the modal view style: (the FloatingViewController.m)
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor clearColor]];
[UIView beginAnimations:nil context:nil];
[self.view setFrame:CGRectMake(0, 480, 320, 480)];
[UIView setAnimationDuration:0.75f];
[self.view setFrame:CGRectMake(0, 0, 320, 480)];
[UIView commitAnimations];
}
wangii
Thats pretty much the solution I found.
I load the view with loadNibNamed and then just add it on top with addSubView, like this:
//Show a view on top of current view with a wait indicator. This prevents all user interactions.
-(void) showWaitView{
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:#"WaitView" owner:self options:nil];
#ifdef __IPHONE_2_1
waitView = [ nibViews objectAtIndex: 0];
#else
waitView = [ nibViews objectAtIndex: 1];
#endif
CGFloat x = self.view.center.x - (waitView.frame.size.width / 2);
CGFloat y = self.view.center.y - (waitView.frame.size.height / 2);
[waitView setFrame:CGRectMake(x,y,waitView.bounds.size.width,waitView.bounds.size.height)];
[self.view addSubview:waitView];
}
Could you elaborate on points 3 and 4?
What I did to give the view the round rect aspect is put it inside a round rect button.
This code will actually allow you to have a small floating view, but if the view is smaller that its parent, the user could interact with the visible part of the parent.
In the end I create my view with the same size, but kept the code just in case.
Gonso
I would strongly consider using a navigation controller to slide in your subview instead of overlaying it. This is the expected model and any small benefit you may think you'll get by doing it your own way will be greatly offset by the principle of (least) surprise.
If you really really have to do it this way, I believe the trick is to add the first table view as a subview of a transparent "holding" view that the view controller maintains. Then add your new sub view as another subview of that.
Again, if you really want to do this, instead of adding a transparent "holding" view, since this pop-up is essentially modal, I would make it a subview directly of the window.
You might want to put in a transparent black shield behind it to prevent touches on the background and focus input on the popup.
But seriously, consider either popping a controller on the stack or using that alert view. Unless you've hired a $$ designer, it's probably not going to look appropriate on the iPhone.
What I did was create a UIViewController on top of my UINavigation controller in my app delegate and made it a property of a singleton object for convenience:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//--- create root navigation controller
self.window.rootViewController = self.navigationController;
//--- create view controller for popups:
popupViewController = [[BaseViewController alloc] init];
popupViewController.view.backgroundColor = [UIColor clearColor];
popupViewController.view.hidden = true; //for rendering optimisation
[self.window addSubview:popupViewController.view];
[AppState sharedInstance].popupViewController = self.popupViewController;
//--- make all visible:
[self.window makeKeyAndVisible];
return YES;
}
At any point in my app, I can then call e.g.
MyViewController * myVC = [[UIViewController alloc] init];
//... set up viewcontroller and its view...
// add the view of the created view controller to the popup view:
[AppState sharedInstance].popupViewController.view.hidden = false;
[[AppState sharedInstance].popupViewController.view addSubview:myVC.view];
The BaseViewController used on the top just inherits from UIViewController and sets up a full-screen view:
//----- in BaseViewController implementation
- (void)loadView {
//------- create root view:
CGRect frame = [[AppState sharedInstance] getScreenFrame];
rootView = [[VCView alloc] initWithFrame:frame];
rootView.backgroundColor = [UIColor whiteColor];
self.view = rootView;
}