views:

1045

answers:

2

In the root table view controller I add a subview that holds an image:

[self.navigationController.navigationBar addSubview:imageView];

Then in a child table view controller that I push onto the stack I set a right UIBarButtonItem:

UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Right"  style:UIBarButtonItemStylePlain target:self action:@selector(rightAction:)];
self.navigationItem.rightBarButtonItem = rightButton;
[rightButton release];

I cannot understand why the button is not displayed in the navigation bar. If I tap (the blank space) the rightAction: method gets invoked so the button "is" there, expect that it is not displayed.

I have tried to send the imageView subview to back in the navigation bar but to no avail. It kind of makes sense since the button actually belong to the UINavigationItem anyway...

Does anybody know how I can make that button display correctly?

Update: the back button does display correctly but it is added by the system though...

A: 

A better way to add a image to a UINavigationBar is to subclass it or make a category and override the drawRect method:

//                                  #Lighter r,g,b,a      #Darker r,g,b,a
#define MAIN_COLOR_COMPONENTS       { 0.153, 0.306, 0.553, 1.0, 0.122, 0.247, 0.482, 1.0 }
#define LIGHT_COLOR_COMPONENTS      { 0.478, 0.573, 0.725, 1.0, 0.216, 0.357, 0.584, 1.0 }

@implementation UINavigationBar (UINavigationBarCategory)

- (void)drawRect:(CGRect)rect {
    if (imageReady) {
        UIImage *img = [UIImage imageNamed: @"navigation_background.png"];
        [img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    } else {
        // Render yourself instead.
        // You will need to adjust the MAIN_COLOR_COMPONENTS and LIGHT_COLOR_COMPONENTS to match your app

       // emulate the tint colored bar
       CGContextRef context = UIGraphicsGetCurrentContext();
       CGFloat locations[2] = { 0.0, 1.0 };
       CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();

       CGFloat topComponents[8] = LIGHT_COLOR_COMPONENTS;
       CGGradientRef topGradient = CGGradientCreateWithColorComponents(myColorspace, topComponents, locations, 2);
       CGContextDrawLinearGradient(context, topGradient, CGPointMake(0, 0), CGPointMake(0,self.frame.size.height/2), 0);
       CGGradientRelease(topGradient);

       CGFloat botComponents[8] = MAIN_COLOR_COMPONENTS;
       CGGradientRef botGradient = CGGradientCreateWithColorComponents(myColorspace, botComponents, locations, 2);
       CGContextDrawLinearGradient(context, botGradient,
       CGPointMake(0,self.frame.size.height/2), CGPointMake(0, self.frame.size.height), 0);
       CGGradientRelease(botGradient);

       CGColorSpaceRelease(myColorspace);


       // top Line
       CGContextSetRGBStrokeColor(context, 1, 1, 1, 1.0);
       CGContextMoveToPoint(context, 0, 0);
       CGContextAddLineToPoint(context, self.frame.size.width, 0);
       CGContextStrokePath(context);

       // bottom line
       CGContextSetRGBStrokeColor(context, 0, 0, 0, 1.0);
       CGContextMoveToPoint(context, 0, self.frame.size.height);
       CGContextAddLineToPoint(context, self.frame.size.width, self.frame.size.height);
       CGContextStrokePath(context);
    }
}

@end

Doing it this way will cause your buttons to show correctly and is less "hacky".

coneybeare
I could subclass the UINavigationBar but the property is read-only in the UINavigationController... the other thing is that the "image" is actually retrieved from a server so it has to be set on the fly.
nicktmro
I have accepted your answer but I would really appreciate your input with the following: if my image is not ready when I display the navbar I get a black background. Any change I could revert to the default blue background/style without using an image?
nicktmro
yes, i will update the code
coneybeare
A: 

I think you should set the navigation item's title view to your imageView.

self.navigationItem.titleView = imageView;

I guess the UINavigationBar displays the UINavigationItems in a subview, and you were adding your UIImageView on top of that subview.

In one of my views I'm displaying a label and an image next to it. I think I just added the label and image view to a view which I then used for the titleView.

Thomas Müller
That would normally work but the titleView does not span across the whole screen. I suspect it is only 300px rather than 320.
nicktmro
I guess you want it as a background image then? OK, then maybe try adding your imageView at index 0 (-insertSubview:atIndex:)
Thomas Müller