UINavigationBar jumping up when app becomes active - iphone

I have a custom UINavigationBar that has a different image background and height than the default one. It's displayed normally but as soon as I go back and forth between apps the background image and buttons inside the navigation bar jump up.
The UINavigationBar is created in a nib and has a custom class that overrides the default implementation to add the image:
#implementation MyUINavigationBar
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"nav.png"];
rect.size.height = 60;
[image drawInRect:rect];
}
#end
At this point the bar isn't displayed correctly. In - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions of my app delegate I fix this with this code:
self.navigationController.view.frame = CGRectMake(0, 20, 320, 460);
self.navigationController.navigationBar.frame = CGRectMake(0, 0, 320, 60);
Now everything shows up correctly. When I switch to another app and go back again the bar jumps up, just as if the frames weren't applied. This happens right after I switch back to the app.
Below are two screenshots showing what's going on. The first one shows the correct version, the other one the faulty one.
Any idea what might be going on? I tried applying the new frames in viewWillAppear and viewDidAppear of the active view or in applicationDidBecomeActive of the app delegate but that didn't help.
https://skitch.com/instromaniac/rtagr/ios-simulator
https://skitch.com/instromaniac/rtaf9/view-not-ok

I spent days to figure this out, here is the trick that really work for a complete, customized backButton.
The backBarButtonItem is totally locked down in the iOS SDK (4.3 as far as I know), so we have to use a leftBarButtonItem that do the job in place of the regular back button.
Whereas the backBarButtonItem has to be defined in the Root View Controller of your UINavigationController, we have to setup our fake BackButton in the child view (ie. nextViewController in my example).
This code is in my Root View Controller (Which is a UITableViewDelegate), in -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
[[self navigationController] pushViewController:nextViewController animated:YES];
here is the graal for displaying our fake back button in a 70px Custom UINavigationBar (Play with the frames to fit your needs) :
-(void)handleBack:(id)sender {
// Simulate the original back button
[self.navigationController popViewControllerAnimated:YES];
}
-(void)viewWillAppear:(BOOL)animated {
// Making a custom button
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[backBtn setImage:[UIImage imageNamed:#"back-button.png"] forState:UIControlStateNormal];
[backBtn setImage:[UIImage imageNamed:#"back-button-hover.png"] forState:UIControlStateHighlighted];
[backBtn setImage:[UIImage imageNamed:#"back-button-disabled.png"] forState:UIControlStateDisabled];
[backBtn setFrame:CGRectMake(6, 4, 60, 30)];
// Binding custom target & action to the button
[backBtn addTarget:self action:#selector(handleBack:) forControlEvents:UIControlEventTouchUpInside];
// Nesting the button in a UIView to position the button anywhere!
UIView *backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60, 70)];
[backView addSubview:backBtn];
// Nesting all of these into a UIBarButtonItem
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:backView];
// Overwrite original backbutton (self.navigationItem.backBarButtonItem DO NOT WORK HERE
self.navigationItem.leftBarButtonItem = backItem;
// Memory clean up
[backItem release];
[backView release];
}
Have fun ;)

Try changing the frame of the navigation controller's view as
self.navigationController.view.frame = CGRectMake(0,0,320,480);
Hope this helps

Related

Hide Navigation Bar but not the back button

i hide my navigation using:
[self.navigationController setNavigationBarHidden:YES animated:YES];
But i need to not hide the back button, it's Possible?
nevan king is right but you can simply change the background image of the navigation bar or set it to nil. If you set it to nil or provide a transparent BG-image you would achieve the effect you need.
For iOS >= 5.0 you could simply set the appearance:
if([navigationBar respondsToSelector:#selector(setBackgroundImage:forBarMetrics:)]) // needed if iOS older than 5.0 is also supported
[navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
You can do that where ever you have a pointer to your navigation bar. E.g. inside of the viewDidLoad method of your ViewController.
For older iOS version you need a workaround by making a category of UINavigationBar and overwrite the drawRect method:
#implementation UINavigationBar (BackgroundImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #""];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end
Both methods are compatible if you want to support all iOS versions.
Thus you should keep in mind, that the back button uses the same background image. So you will need to make a custom one.
UIImage *bgImageNormal = [UIImage imageNamed:#"backButtonImage.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage: bgImageNormal forState:UIControlStateNormal];
button.frame= CGRectMake(0.0, 0.0, bgImageNormal.size.width, bgImageNormal.size.height);
[button addTarget:self action:#selector(navigationBarBackButtonTouchUpInside:) forControlEvents:UIControlEventTouchUpInside]; // your action method here
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithCustomView:button];
self.navigationItem.leftBarButtonItem = closeButton;
[closeButton release];
This code needs to be implemented for each ViewController you are pushing to your navigation bar. A good place for it is also inside the viewDidLoad method.
The back button is created by the navigation bar and always part of it, so it's not possible. You could hide and re-show the navigation bar when your user touches on the screen (this is what the Photos app does when you look at a single photo) or create a button and have it permanently on the top left of the screen. You could also make the navigation bar partly transparent so that the content underneath shows up.

Navigation Back Button does not show,how to add back button to UINavigationItem

I add UINavigationBar via Library to view. I also add UINavigationItem to this NavigationBar.
In viewController.m,I added the following code but back button doesn't show.
self.navigationItem.title = #"List";
self.navigationItem.backBarButtonItem.title = #"Back";
Try this:
self.navigationItem.leftItemsSupplementBackButton = YES;
or
navigationItem.leftItemsSupplementBackButton = true
If you customize your navigation controller with UIBarButtonItems the framework removes the back button by default, since it assumes you are customizing the Navigation bar. Use that line to add the back button in again.
self.navigationItem.backBarButtonItem will be shown only after your have pushed another one view to navigation stack, controlled by self.navigationController, if no left button on navigation bar is displayed.
From Apple docs:
When this item is the back item of the navigation bar—when it is the next item below the top item—it may be represented as a back button on the navigation bar. Use this property to specify the back button. The target and action of the back bar button item you set should be nil. The default value is a bar button item displaying the navigation item’s title.
Try this code,
**To hide your default back button use this,**
self.navigationItem.hidesBackButton = YES;
UIImage* image = [UIImage imageNamed:#"back.png"];
CGRect frame = CGRectMake(0, 0, image.size.width, image.size.height);
UIButton* backbtn = [[UIButton alloc] initWithFrame:frame];
[backbtn setBackgroundImage:image forState:UIControlStateNormal];
[backbtn setShowsTouchWhenHighlighted:YES];
[backbtn addTarget:self action:#selector(goBack) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backbtn];
[self.navigationItem setLeftBarButtonItem:backButtonItem];
[backButtonItem release];
[backbtn release];
Action Event for back button:
-(IBAction)goBack{
//ur code here
}
Try this code may be it's help to u
UIButton *moreButton1 = [UIButton buttonWithType:UIButtonTypeCustom];
[moreButton1 setImage:[UIImage imageNamed:#"left_arrow.png"] forState:UIControlStateNormal];
//[moreButton setImage:[UIImage imageNamed:#"Button_OtherInfo_Active.png"] forState:UIControlStateHighlighted];
[moreButton1 addTarget:self action:#selector(backClick) forControlEvents:UIControlEventTouchUpInside];
[moreButton1 setFrame:CGRectMake(0, 0, 50,30)];
self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc] initWithCustomView:moreButton1];
put this code in viewDidLoad
-(void)backClick
{
[self.navigationController popViewControllerAnimated:YES];
}
This is a bit old, but in case someone is looking for an answer...
The back button shows up automatically, but the current view (not the one being pushed) needs to have a title. eg:
- (void)viewDidLoad
{
self.title = #"Home";
[super viewDidLoad];
}
Then, when you push a view onto the view stack with
[self.navigationController pushViewController:aViewController animated:YES];
the back button shows up. No need to mess with UINavigationItem or UINavigationBar. Use those to customize the navigation bar. Take a look at the example project called NavBar, part of xcode.

setToolbarItems issue

I added toolbar to on screen of navigation based application using the following code
//Create an array to hold the list of bar button items
NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:3];
//Add buttons
//load the image
UIImage *buttonImage ;
buttonImage = [UIImage imageNamed:#"test.png"];
//create the button and assign the image for window width and level
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:#selector(WWL:) forControlEvents:UIControlEventTouchUpInside];
[button setImage:buttonImage forState:UIControlStateNormal];
//set the frame of the button to the size of the image (see note below)
button.frame = CGRectMake(0, 0, buttonImage.size.width, buttonImage.size.height);
//create a UIBarButtonItem with the button as a custom view
WindowWidthZoom = [[UIBarButtonItem alloc] initWithCustomView:button ];
[items addObject:WindowWidthZoom ];
[self setToolbarItems:items];
[[self navigationController] setToolbarHidden:NO animated:NO];
but when leave the screen , I noticed that the toolbar didn't disappear in the other screens , any suggestion how to hide it before leaving this screen to avoid its presence in other screens , and how to change its color to black
You might add the following to the -viewWillAppear method of all your other view controllers:
[self.navigationController setToolbarHidden:YES animated:NO];
In the view controller where you want the toolbar to appear, make sure you setToolbarHidden to NO also in the -viewWillAppear method. Doing so in the -viewDidLoad method is not enough because this method is not called every time a view appears. For example, when you hit the Back button of a navigation controller and return to a previous view controller, since that view controller has already been loaded, it may not need to load again (and so -viewDidLoad will not be called.)
Please change your last line code:
[[self navigationController] setToolbarHidden:NO animated:NO];
to:
[self setToolbarHidden:NO animated:NO];
And make sure call it in:
- (void)viewDidAppear:(BOOL)animated;

Custom UINavigationBar button not displaying

(edited: added more information at bottom)
Firstly I have looked through similar posts and tried their answers but with no luck :( I have a custom navigation bar (just a custom background image) and I'm trying to add a custom back button.
// custom back button.
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *backImg = [UIImage imageNamed:#"btn_back.png"];
backBtn.titleLabel.text = #"";
[backBtn setBackgroundImage:backImg forState:UIControlStateNormal];
[backBtn addTarget:self action:#selector(backPressed) forControlEvents:UIControlEventTouchUpInside];
backBtn.frame = CGRectMake(0, 0, 54, 33);
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backBtn];
self.navigationItem.leftBarButtonItem.title = #"";
The above code is meant to add the button but it does not display on the nav bar. I can still click the area where its meant to appear and it does bring me back to the previous view?! removing the above code displays the standard back button.
Any ideas? Thanks in advance!
(edit)
Hi again guys,
I tried all your suggestions and still no luck :( I probably should have mentioned earlier that I have a custom nav bar image using the following code. This might be affecting the display of my custom back button image.
This code displays a custom image depending upon a parameter I set. Thanks again for further help!
// custom navigation bar image
#implementation UINavigationController (CustomImage)
// set the background image for the nav bar.
- (void) setCustomNavBar:(NSInteger)screen {
UIImage *navBarImg;
switch (screen) {
case kCreateHuntScreenIdentifier:
navBarImg = [UIImage imageNamed:#"title_create-hunt.png"];
break;
case kCreateLocationsScreenIdentifier:
navBarImg = [UIImage imageNamed:#"title_create-location.png"];
break;
case kListNewLocationsScreenIdentifier:
navBarImg = [UIImage imageNamed:#"title_choose-location.png"];
break;
default:
break;
}
UIImageView *imgView = [[UIImageView alloc] initWithImage:navBarImg];
[[[self.navigationBar subviews] objectAtIndex:0] removeFromSuperview];
[self.navigationBar addSubview:imgView];
[imgView release];
}
#end
Thanks again for all your advice! I finally found a solution :D
Very quickly I needed to be able to change the background image for a navigation bar from view to view when I pushed or popped the stack.
Using the most popular methods such as overriding the UINavigationBar's drawRect would only partly work, it would work on the root view but then push the image to the front of the navigation bar's stack for every other screen no matter if I sent it to the back, etc.
I found the solution here: http://sebastiancelis.com/2009/12/21/adding-background-image-uinavigationbar/
Take a read, it works great :)
UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
[btn setBackgroundImage:[UIImage imageNamed:#"imgname.png"] forState:UIControlStateNormal];
[btn addTarget:self action:#selector(method_name:) forControlEvents:UIControlEventTouchUpInside];
btn.frame=CGRectMake(3, 2, 53, 30);
UIBarButtonItem *btnBack=[[UIBarButtonItem alloc] initWithCustomView:btn];
self.navigationItem.leftBarButtonItem=btnBack;
[btnBack release];
[btn release];
Try,
self.navigationItem.hidesBackButton = YES;
befor writing the code for .leftBarButtonItem .Hope it helps

iPhone custom navigation bar with button doesnt click

Ive got an iPhone/iPad universal application and I wanted to have a custom navigation bar where the top half of the nav bar contained our companies logos, and the bottom half was the standard navigation bar.
I figured out how to do this, showing in the code below, but my UIButton "logosButton" doesnt always respond to being clicked, it appears as though only certain parts of the button are active, and others dont do anything at all... I cannot figure out why this is.
- (void)viewDidLoad {
[super viewDidLoad];
[[self view] addSubview: navController.view];
float width = IS_IPAD ? 768.0f : 320.0f;
float logosHeight = IS_IPAD ? 20.0f : 20.0f;
float barHeight = IS_IPAD ? 32.0f : 32.0f;
self.navBar = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, logosHeight, width, barHeight)];
UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, logosHeight)];
UIButton *logosButton = [[UIButton alloc] init];
[logosButton setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState:UIControlStateNormal];
[logosButton setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState:UIControlStateHighlighted];
[logosButton addTarget:self action:#selector(logosButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[logosButton setFrame: CGRectMake(0, 0, width, logosHeight)];
[tempView addSubview: logosButton];
[[self view] addSubview: tempView];
[tempView release];
[[self view] addSubview: self.navBar];
self.navItem = [[UINavigationItem alloc] initWithTitle: #"Home"];
[self.navBar pushNavigationItem:self.navItem animated:NO];
}
The method: logosButtonClicked does get fired every now and then when I click on the UIButton, but I clearly am clicking on certain spots where nothing happens at all...
Very frustrating, I dont seem, to see a pattern in regards to where its active, but could someone please help out here?
EDIT
I think I have just stumbled across something, I changed the button to a UIButtonTypeRoundedRect and got rid of the images (and also made it larger) and it appears that I cannot click on the bottom OR top sections of the button where the button is rounded. So the middle rectangular section is the only section where I can click... why would this be?
EDIT 2
For anyone reviewing this question, please see taber's latest edit on his answer. The Navigation Controller is eating touches for some reason, and I need to figure out why this is so, could be a bug?
FINAL ANSWER :)
Okay after reviewing the project it looks like the UINavigationController that is positioned below the button is eating touches globally. Which is definitely weird because it was added as a subview BELOW your button. So there must be some kind of funky frame/touch-eating going on with the UINavigationController. I tried to set navigationController.titleView.userInteractionEnabled = NO but to no avail. If anyone knows how to basically make UINavigationController and UINavigationBar not eat touches (I'm talking about the background where no buttons exist) then please chime in. The UIButton touches work just fine when the UINavigationController isn't added to the view.
Original Answer
It may be some other UI elements in [self view] or tempView sitting on top of the button and intercepting taps. You might want to try either commenting out everything else in the view(s) and/or try setting the userInteractionEnabled property on them like this:
[otherUIElement setUserInteractionEnabled: NO];
EDIT:
This code makes it so that you CAN click the round rect edges but NOT the title text. So I suspect that it's some sort of subview preventing the button from catching the tap.
[logosButton addTarget:self action:#selector(logosButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[logosButton setFrame: CGRectMake(0, 0, 320.0, 50.0)];
[logosButton setTitle: #"HELLO" forState: UIControlStateNormal];
[logosButton.titleLabel setUserInteractionEnabled: YES];
EDIT #2:
Try using this subclassed button and see if the issue still occurs:
// NavBtn.h
#interface NavBtn : UIButton {
}
-(id)initWithTitle:(NSString *)text;
#end
// NavBtn.m
#import "NavBtn.h"
#implementation NavBtn
- (id)initWithTitle:(NSString *)text {
if ((self = [super initWithFrame: CGRectMake(0, 0, 320, 50)])) {
[self setTitle: text forState: UIControlStateNormal];
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
[self setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState: UIControlStateNormal];
[self setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState: UIControlStateHighlighted];
}
return self;
}
// i guess you shouldn't need to mess with layoutSubviews
#end
To load it into your view:
#import "NavBtn.h"
... in viewDidLoad, etc ...
NavBtn *btn = [[NavBtn alloc] initWithTitle: #"hey"];
[self.view addSubview: btn];
[btn release];
If THAT doesn't work, there's got to be some kind of third party library doing some funky category overriding of your UIButton class or something.