overriding UINavigationBar drawRect function doesnt work - iphone

I have a simple app with a nav bar controller and I would like to change its navigation bar while overriding the drawRect function. I read in many places here that all I need to do is just to paste the code below above my appDelegate. Sadly, it doesnt seem to do anything for me. I tried as a start to just have the color of the nav bar changed, before i try to add an image to it, but again, nothing happens. What am i missing here
I tired to insert this code above the AppDelegate:
#implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
UIColor *color = [UIColor redColor];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColor(context, CGColorGetComponents( [color CGColor]));
CGContextFillRect(context, rect);
}
#end
And with the background image:
#implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
// Drawing code
UIImage *img = [UIImage imageNamed: #"13.png"];
[img drawInRect:CGRectMake(0, 0, 320, self.frame.size.height)];
}
#end
Thanks for the help!

This code declares a category on UINavigationBar and redefines the behaviour of its drawRect: method. Try to put the code snippet (second one) at the end of the .m file of the app delegate.
Although the first should work, another more clean option is to write the category in a separate file you will include in the app delegate.
Also make sure the picture you are loading exists in the app bundle.

Ok - solution found! This doesnt seem to work on the iPhone 5.0 simulator!

Related

How to overide UIToolbar method with later version of iOS 4.2

This code works fine with iPad Simulator 4.2, but not with later version of iOS4.3 or after that.I am not able to Override the UIToolbar class methods.
#implementation UIToolbar (CustomImage)
- (void)drawRect:(CGRect)rect
{
UIImage *image = [[UIImage imageNamed:#"ToolBar.png"] retain];
[image drawInRect:rect];
[image release];
}
//return 'best' size to fit given size. does not actually resize view. Default is return existing view size
- (CGSize)sizeThatFits:(CGSize)size {
CGSize result = [super sizeThatFits:size];
result.height = 80;
return result;
};
What would be the alternate solution for this ?Please guide me.
In later version ..- (void)drawRect:(CGRect)rect is never called .
Running with iPad Simulator 4.2 code works fine but with iPad Simulator 4.3 drawRect in never called.
Below is the Screenshot of Toolbar:
What about something like this?
#implementation UIToolbar (UIToolbarCategory)
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
if([self isMemberOfClass: [UIToolbar class]]){
[super drawRect:rect];
UIImage *image = [UIImage imageNamed:#"bar_gradient.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
}
#end
you are implementing it as a category, you need to subclass UIToolBar based on the iOS5 change log
In the iOS 5 beta, the UINavigationBar,
UIToolbar, and UITabBar implementations have changed so that the
drawRect: method is not called on instances of these classes unless it
is implemented in a subclass.
Apps that have re-implemented drawRect: in a category on any of these
classes will find that the drawRect: method isn’t called.
UIKit does link-checking to keep the method from being called in apps
linked before iOS 5 but does not support this design on iOS 5 or
later. Apps can either:
Use the customization API for bars that in iOS 5 and later, which is the preferred way.
Subclass UINavigationBar (or the other bar classes) and override drawRect: in the subclass.

iOS Dynamic Change UINavigationBar's Background With Image

I have read this and change UINavigationBar's background:
#implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"top-with-logo.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end
you see, I add a image named top-with-logo.png, and I want to change the background view by adding an image named top-without-logo.png. But the code above will change the background forever and i cannont change any more. Do you know how?
Thank you very much.
I'm not sure I understand what you mean, but you can place a Boolean ivar on your app's delegate. then in the function you load top-with-logo.png if it's true/false and load top-without-logo.png if it's the other value. then, when you want to change the logo, just change the Boolean's value and call setNeedsDisplay on the navigationBar.
if you use xib files, you can also subclass UINavigationBar, and instead of using a catagory you override the drawRect function and place the variable as an instance variable as a subclass, I believe it is cleaner, but you can only set that up in Interface builder ( otherwise there's no way to tell a UINavigationController to use a different class for the navigationBar property )
You can use,
UINavigationBar *navigationBar = self.navigationController.navigationBar;
UIImage *image = [UIImage imageNamed: #"NavBar-Wood.png"];
[navigationBar setBackgroundImage:image forBarMetrics: UIBarMetricsDefault];
self.navigationController.navigationBar.tintColor = [UIColor brownColor];

Category on UINavigationBar - only for certain controllers

I successfully implemented a navigation bar with custom background following the answer posted at Custom background for UINavigationBar problems.
However, I would like to have the standard navigation bar for some of my controllers and I have no clue how I can achieve this.
If I start a new project based on the Navigation-based Application template and just add the UINavigationBar category in separate .h and .m files, this category is applied immediately. No includes or whatever are necessary. How does this work?
Thanks for your help!
Here's a quick hack - use the tag property of your navigation bar to turn on the custom code i.e.
#implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
if (tag < 500) {
// Drawing code
UIImage *img = [UIImage imageNamed: #"navbar_background.png"];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, 320, self.frame.size.height), img.CGImage);
} else {
// Do the default drawing
}
}
#end
Now, navigation controllers with a tag less than 500 use your custom background. If you set the tag to be > 500, you get the default behaviour.
EDIT
As #MikeWeller correctly pointed out, we don't have access to the initial implementation of drawRect, our category has overridden it.
Take a look at this link for a solution - basically, it's a macro that you can include that gives you an extra method :
#implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
if (tag < 500) {
// Drawing code
UIImage *img = [UIImage imageNamed: #"navbar_background.png"];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, 320, self.frame.size.height), img.CGImage);
} else {
// Do the default drawing
invokeSupersequent(rect);
}
}
#end
NB I haven't tried this myself but have used other articles from this blog before with great success so I trust it :) Let us know how you get on!
#implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
if (tag < 500) {
// Drawing code
UIImage *img = [UIImage imageNamed: #"navbar_background.png"];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, 320, self.frame.size.height), img.CGImage);
} else {
// Do the default drawing
}
}
#end
Remeber this method will not work in iOS 5.0 because apple has changed the implementation of UINavigationBar so instead create a subclass of UINavigationBar and override the method there instead of creating category.

Custom UINavigationController UINavigationBar

Basically I want a custom UINavigationBar. I don't want it to be "translucent" or anything, like the pictures app.
I basically want to completely remove it, but I still want to be able to add back buttons and such when navigation controllers are pushed, and I want the views (EG: UITableViewController) to be pushed down below it.
Like this:
Any ideas how to achieve this at all?
Thanks
#implementation UINavigationBar (background)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:#"navigationbar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end
basically, its not completely see through - its a visual lie. The only way to do it realistically is to override UINavigationBar's drawRect: method, as shown above.
To see through the UINavigationBar, if you choose to have one, just:
self.navigationController.navigationBar.translucent=YES;
You'll have to change the tint/color to match the background if you want it to appear like the image you posted.
At the beginning of your AppDelegate subclass UINavigationBar as below:
#interface CustomNavBar : UINavigationBar
#end
#implementation CustomNavBar
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:#"bar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
and then in the AppDelegate do this magic:
//Set custom NavigationBar
[self.navController setValue:[[CustomNavBar alloc]init] forKeyPath:#"navigationBar"];
//Set tint to match bar.png
self.navController.navigationBar.tintColor = [UIColor colorWithRed:0.93 green:0.43 blue:0 alpha:1];
//Set font for NavigationBar
[self.navController.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"Comfortaa-Bold" size:20], UITextAttributeFont, nil]];
That should give you a lot more control over UINavigationController look & feel.
Hard to tell, could be the UINavigationBar is there and color matches the UIView background or, there is no UINavigationBar, just a view with custom buttons and UILabel on top. Pick an approach and code it, or ask the question again with more specifics.

Best point to overwrite the navigationBar property of navigationController

I'm overwriting UINavigationController to replace the default navigationBar property with an instance of my own subclass of UINavigationBar. So I tried something like
_navigationBar = [[SBNavigationBar alloc] init];
in my -initWithRootViewController:. But that didn't work out as I expected it. There's still the default navigationBar being displayed.
So what's the best point to overwrite the navigationBar?
Thanks in advance
–f
If you check the documentation http://developer.apple.com/iphone/library/documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html, you'll see that the navigationBar property is read-only.
To have a custom navigationBar you can use Categories for example. You will find many questions answering this here on stackoverflow.
One simple version is putting an image in drawRect: like so...
#implementation UINavigationBar (Custom)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"bg_toolbar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
#end