Couldn't UIToolBar be transparent? - cocoa-touch

I try the following code, but it doesn't work.
[helloToolbar setBackgroundColor:[UIColor clearColor]];

To make a completely transparent toolbar, use the method described here. In a nutshell, create a new TransparentToolbar class that inherits from UIToolbar, and use that in place of UIToolbar.
TransarentToolbar.h
#interface TransparentToolbar : UIToolbar
#end
TransarentToolbar.m
#implementation TransparentToolbar
// Override draw rect to avoid
// background coloring
- (void)drawRect:(CGRect)rect {
// do nothing in here
}
// Set properties to make background
// translucent.
- (void) applyTranslucentBackground
{
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.translucent = YES;
}
// Override init.
- (id) init
{
self = [super init];
[self applyTranslucentBackground];
return self;
}
// Override initWithFrame.
- (id) initWithFrame:(CGRect) frame
{
self = [super initWithFrame:frame];
[self applyTranslucentBackground];
return self;
}
#end
(code from the blog post linked above)

In iOS 5, simply call setBackgroundImage and pass a transparent image.
Here's how I do it (I dynamically generate transparent image):
CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextFillRect(context, rect);
UIImage *transparentImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[toolbar setBackgroundImage:transparentImage forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];

The best you can do is using
[helloToolbar setBarStyle:UIBarStyleBlack];
[helloToolbar setTranslucent:YES];
This will get you a black but translucent toolbar.

Transparent (iOS 5.0):
[toolbar setBackgroundImage:[[UIImage alloc] init] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
Translucent:
[toolbar setBarStyle:UIBarStyleBlack];
[toolbar setTranslucent:YES];

A cumulative solution for all devices, from oldest iOS 3.0 (iPhone 1) to newest iOS 6.1 (iPad mini).
#implementation UIToolbar (Extension)
- (void)drawRect:(CGRect)rect
{
if (CGColorGetAlpha(self.backgroundColor.CGColor) > 0.f)
{
[super drawRect:rect];
}
}
- (void)setTransparent
{
//iOS3+
self.backgroundColor = [UIColor clearColor];
//iOS5+
if ([self respondsToSelector:#selector(setBackgroundImage:forToolbarPosition:barMetrics:)])
{
[self setBackgroundImage:[[UIImage new] autorelease] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
}
//iOS6+
if ([self respondsToSelector:#selector(setShadowImage:forToolbarPosition:)])
{
[self setShadowImage:[[UIImage new] autorelease] forToolbarPosition:UIToolbarPositionAny];
}
}
#end
When you want a transparent toolbar, call setTransparent on it.
When you want a non-transparent toolbar, set a backgroundColor of your choice or add an imageView by yourself.

Another solution would be to define a category for UIToolbar:
#implementation UIToolbar(Transparent)
-(void)drawRect:(CGRect)rect {
// do nothing in here
}
#end
In the IB set the toolbar as Black Translucent and non opaque.

We've just noticed that overriding drawRect doesn't work anymore with iOS 4.3. It's not called anymore (edit: seems to be only in Simulator). Instead drawLayer:inContext: is called.
A great solution was posted here
Now you can set each UIToolbar object transparent, by setting its tintColor to [UIColor clearColor] :)

With iOS 5 the following works:
UIToolbar *bar = [[UIToolbar alloc] initWithFrame:CGRectZero];
if (bar.subviews.count > 0)
[[[bar subviews] objectAtIndex:0] removeFromSuperview];
This is because the background is now a subview. This code is safe even with new iterations of iOS, but it may stop working. This is not private API usage, your app is safe to submit to the store.
Make sure you remove the backgroundView before adding any UIBarButtonItems to the bar. Or my code will not work.

I just tested the following with iOS 4.3 on simulator and phone, seems to work fine. Subclass UIToolbar, provide one method:
- (void)drawRect:(CGRect)rect
{
[[UIColor colorWithWhite:0 alpha:0.6f] set]; // or clearColor etc
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
}

toolbar.barStyle = UIBarStyleBlackTranslucent;

This works in iOS5.1 with pretty minimal effort. I am matching up the size, as only the background will have the same frame size as the toolbar itself. You could use other criteria, of course.
Enjoy.
Create a subclass of UIToolbar as follows:
.h:
#import <UIKit/UIKit.h>
#interface UIClearToolbar : UIToolbar
#end
.m:
#import "UIClearToolbar.h"
#implementation UIClearToolbar
- (void)layoutSubviews {
// super has already laid out the subviews before this call is made.
[self.subviews enumerateObjectsUsingBlock:^(UIView* obj, NSUInteger idx, BOOL *stop) {
if (CGSizeEqualToSize(self.frame.size, obj.frame.size) ||
self.frame.size.width <= obj.frame.size.width) { // on device, the background is BIGGER than the toolbar.) {
[obj removeFromSuperview];
*stop = YES;
}
}];
}
#end

Thanks #morais for your solution - here's the code translated to MonoTouch:
public class TransparentToolbar : UIToolbar
{
public TransparentToolbar()
{
init();
}
public TransparentToolbar(RectangleF frame) : base(frame)
{
init();
}
void init()
{
BackgroundColor=UIColor.Clear;
Opaque=false;
Translucent=true;
}
public override void Draw(RectangleF rect)
{
}
}

Related

Does it make sense to add ATMHud to tabBarController.view

When i try to add ATMHud to uitableviewcontroller subview it does work but it doesn't disable the scrolling and if the tableview is not on top i can't see the hud view. What i did was added to teh tabBarController.view that works but i want find out if this is a good idea or later on i might have issues with it.
Another question is tabBarController.view frame is that the whole screen or just the bottom part. How come atmhud shows in the middle of the screen?
Thanks in advance!
Yan
============
Found a blog post that shows how to reset self.view and add tableview separately in uitableviewcontroller
UITableViewController and fixed sub views
- (void)viewDidLoad {
[super viewDidLoad];
if (!tableView &&
[self.view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)self.view;
}
self.view = [[[UIView alloc] initWithFrame:
[UIScreen mainScreen].applicationFrame] autorelease];
self.tableView.frame = self.view.bounds;
self.tableView.contentInset = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0);
[self.view addSubview:self.tableView];
UIView *fixedBar = [[UIView alloc] initWithFrame:
CGRectMake(0.0, 0.0, self.view.bounds.size.width, 44.0)];
fixedBar.backgroundColor = [UIColor colorWithRed:
0.0 green:1.0 blue:0.0 alpha:0.7];
[self.view addSubview:fixedBar];
[fixedBar release];
}
After this when add hud to self.view you will be able to disable the tableview on the bottom.
Let me know if this a good way to setup the tableview
The problem with using the tab bar is that the hud is now modal, and the user cannot change the tab.
It sounds like the tableview is not your primary viewm, as it can get "covered up". If its not the primary view, then add the ATMHud to self.view. If the tableView is the same as self.view, then add a new transparent view to it, then add the HUD to that view.
The tabBarController.view is the view that hosts the tabbed views - if you want to see its size (or frame) log it using NSStringFromCGRect(self.tabBarController.frame);
EDIT: I just did a test, the ATMHud DOES block the UI. All I can think of is that you have not inserted it where you need to (at the top of current view's subviews.) I have a demo project where I do this:
hud = [[ATMHud alloc] initWithDelegate:self];
[self.view addSubview:hud.view];
[hud setCaption:#"Howdie"];
[hud setActivity:YES];
[hud show];
[hud hideAfter:5];
A button under the hud is not active - in fact nothing in the view is active (probably the Nav Bar would be live though)
If you want an ARCified and field tested version, you can grab it here
EDIT2: The solution to your problem is below. Note that ATMHud blocks clicks from getting to the table, and the code below stops the scrolling:
- (void)hudWillAppear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = NO;
}
- (void)hudDidDisappear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = YES;
}
Dump the views:
#import <QuartzCore/QuartzCore.h>
#import "UIView+Utilities.h"
#interface UIView (Utilities_Private)
+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;
#end
#implementation UIView (Utilities_Private)
+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
[str appendFormat:#" %#: frame=%# bounds=%# layerFrame=%# tag=%d userInteraction=%d alpha=%f hidden=%d\n",
NSStringFromClass([a class]),
NSStringFromCGRect(a.frame),
NSStringFromCGRect(a.bounds),
NSStringFromCGRect(a.layer.frame),
a.tag,
a.userInteractionEnabled,
a.alpha,
a.isHidden
];
}
#end
#implementation UIView (Utilities)
+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
while(v) {
[self appendView:v toStr:str];
v = v.superview;
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
if(v) [self appendView:v toStr:str];
for(UIView *a in v.subviews) {
[self appendView:a toStr:str];
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
#end

UIPageControl doesn't properly react to taps

In my TestApp, I created a class "Carousel" which should let me create a swipe menu with a UIPageControl in an easy way (by simply creating an instance of the class Carousel).
Carousel is a subclass of UIView
At init, it creates an UIView, containing UIScrollView, UIPageControl
I can add further UIViews to the scroll view
I don't know if this is the proper way to do it, but my example worked quite well in my TestApp. Swiping between pages works perfectly and the display of the current page in the UIPageControl is correct.
If there were not one single problem: The UIPageControl sometimes reacts to clicks/taps (I only tested in Simulator so far!), sometimes it doesn't. Let's say most of the time it doesn't. I couldn't find out yet when it does, for me it's just random...
As you can see below, I added
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
to my code. I thought this would do the proper handling of taps? But unfortunately, pageChange doesn't get always called (so the value of the UIPageControl doesn't change every time I click).
I would appreciate any input on this because I couldn't find any solution on this yet.
This is what I have so far:
Carousel.h
#import <UIKit/UIKit.h>
#interface Carousel : UIView {
UIScrollView *scrollView;
UIPageControl *pageControl;
BOOL pageControlBeingUsed;
}
- (void)addView:(UIView *)view;
- (void)setTotalPages:(NSUInteger)pages;
- (void)setCurrentPage:(NSUInteger)current;
- (void)createPageControlAt:(CGRect)cg;
- (void)createScrollViewAt:(CGRect)cg;
#end
Carousel.m
#import "Carousel.h"
#implementation Carousel
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Create a scroll view
scrollView = [[UIScrollView alloc] init];
[self addSubview:scrollView];
scrollView.delegate = (id) self;
// Init Page Control
pageControl = [[UIPageControl alloc] init];
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
[self addSubview:pageControl];
}
return self;
}
- (IBAction)pageChange:(id)sender {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:TRUE];
NSLog(#"%i", pageControl.currentPage);
}
- (void)addView:(UIView *)view {
[scrollView addSubview:view];
}
- (void)createPageControlAt:(CGRect)cg {
pageControl.frame = cg;
}
- (void)setTotalPages:(NSUInteger)pages {
pageControl.numberOfPages = pages;
}
- (void)setCurrentPage:(NSUInteger)current {
pageControl.currentPage = current;
}
- (void)createScrollViewAt:(CGRect)cg {
[scrollView setPagingEnabled:TRUE];
scrollView.frame = cg;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*pageControl.numberOfPages, scrollView.frame.size.height);
[scrollView setShowsHorizontalScrollIndicator:FALSE];
[scrollView setShowsVerticalScrollIndicator:FALSE];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float frac = scrollView.contentOffset.x / scrollView.frame.size.width;
NSUInteger page = lround(frac);
pageControl.currentPage = page;
}
#end
ViewController.m (somewhere in viewDidLoad)
Carousel *carousel = [[Carousel alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
for (int i=0; i<5; i++) {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i * 320, 0, 320, 420)];
UIColor *color;
if(i%3==0) color = [UIColor blueColor];
else if(i%3==1) color = [UIColor redColor];
else color = [UIColor purpleColor];
view.backgroundColor = color;
[carousel addView:view];
view = nil;
}
[carousel setTotalPages:5];
[carousel setCurrentPage:0];
[carousel createPageControlAt:CGRectMake(0,420,320,40)];
[carousel createScrollViewAt:CGRectMake(0,0,320,420)];
Your code is correct. Most likely the frame of your pageControl is pretty small, so theres not a lot of area to look for touch events. You would need to increase the size of the height of pageControl in order to make sure taps are recognized all of the time.

Objective C, rounded corner custom window?

I have a subclass of NSWindow to customize one of my windows for my app.
I have everything set, but I am not sure how to make the corners round.
Currently, my window is a transparent rectangular window with some buttons, labels, and a textfield in it.
The class includes:
#import "TransparentRoundRectWindow.h"
#implementation TransparentRoundRectWindow
-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
if (self) {
[self setAlphaValue:0.75];
[self setOpaque:YES];
[self setHasShadow:YES];
[self setBackgroundColor:[NSColor clearColor]];
}
return self;
}
-(BOOL)canBecomeKeyWindow
{
return YES;
}
I just need to make the corners round now. I tried searching for similar situations and saw some of them explaining to override the drawRect method but I couldn't get them to work.
How could I do this?
(I'm using Mac OS X Lion)
Thanks in advance.
You need to set to Your window Opaque to NO. And subclass Your window's view.
Window subclass:
-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
if (self) {
[self setOpaque:NO];
[self setHasShadow:YES];
[self setBackgroundColor:[NSColor clearColor]];
}
return self;
}
-(BOOL)canBecomeKeyWindow
{
return YES;
}
Window's view subclass:
- (void)drawRect:(NSRect)rect
{
NSBezierPath * path;
path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:8 yRadius:8];
[[NSColor colorWithCalibratedRed:0 green:0 blue:0 alpha:0.75] set];
[path fill];
}
Result:
More explanation how to do this:
Create new NSView class and paste "Window's view subclass" code which I wrote in it. Then go to Your window's view.
Here is window's view click on it:
Go to the Identity inspector and set class to your created class:

Objective C - Help with changing background color when UIButton is pressed

I am new to programing and any help is appreciated. I am trying to change the background color of a button once it has been pressed. I have tried setBackgroundColor without success. I am not sure that it is compatible with UIButton. Is there any way to programatically accomplish such a task? All thoughts and suggestions are appreciated.
I woudl suggest creating a simple image that contains the background color you want and setting that via the existing methods in the UIButton. (check Wrights Answer for the doc link).
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
NSString* fileLocation = [[NSBundle mainBundle] pathForResource:#"buttonBG" ofType:#"png"];
UIImage* bgImage = [UIImage imageWithContentsOfFile:fileLocation];
if (bgImage != nil) { // check if the image was actually set
[button setBackgroundImage:bgImage forState:UIControlStateHighlighted];
} else {
NSLog(#"Error trying to read the background image");
}
That should do the trick. There might be an even better way to create the necessary image on the fly, but that's stuff I'm not firm in.
[edit: a bit more verbose code ]
Assuming you have an unadorned custom button with a title of "On" for the normal state:
- (IBAction) toggleButtonState {
if ([toggleButton titleForState:UIControlStateNormal] == #"On") {
[toggleButton setTitle: #"Off" forState:UIControlStateNormal];
[toggleButton setBackgroundColor:[UIColor redColor]];
}
else {
[toggleButton setTitle: #"On" forState:UIControlStateNormal];
[toggleButton setBackgroundColor:[UIColor greenColor]];
}
}
All the other buttons have an image placed in front of the view, so at most you'll see the corners change if the image doesn't completely fill the space.
I'd also suggest using an image, but for learning purposes, this will work.
Ive just been having the same issue and ended up using a UIButton subclass to tackle the issue. I used gradients simply because it looked a bit better if you have no need for them you can simply remove them. I have explained the process I used and included the full code at the bottom of the post.
Firstly add properties for the layers.I created two layers one for the base gradient and one for a gloss to add a little bit of style.
#interface gradientButton()
#property (nonatomic, strong) CAGradientLayer* gradientLayer;
#property (nonatomic, strong) CAGradientLayer* glossyLayer;
#end
Then either in -(void)awakeFromNib or in -(id)initWithFrame:(CGRect)frame
,depending on if you will load from storyboard or code respectively, configure the gradients and add the layers, round your corners off and customize the font highlight color.
-(void)awakeFromNib
{
_gradientLayer = [[CAGradientLayer alloc] init];
_gradientLayer.bounds = self.bounds;
_gradientLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
[self.layer insertSublayer:_gradientLayer atIndex:0];
self.layer.cornerRadius = 5.0f;
self.layer.masksToBounds = YES;
self.layer.borderWidth = 1.0f;
_glossyLayer = [[CAGradientLayer alloc] init];
_glossyLayer.bounds = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height/2);
_glossyLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/4);
[self.layer addSublayer:_glossyLayer];
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self setTitleColor:[UIColor yellowColor] forState:UIControlStateHighlighted];
}
Next, override - (void)drawRect:(CGRect)rect to apply your layers and define your colors.
#define GRADIENT_TOP [UIColor colorWithRed:38.0/255.0 green:78.0/255.0 blue:54.0/255.0 alpha:1]
#define GRADIENT_BOTTOM [UIColor colorWithRed:44.0/255.0 green:71.0/255.0 blue:56.0/255.0 alpha:1]
#define GLOSS_TOP [UIColor colorWithRed:0.70f green:0.70f blue:0.70f alpha:0.95f]
#define GLOSS_BOTTOM [UIColor colorWithRed:0.70f green:0.70f blue:0.70f alpha:0.35f]
#define GRADIENT_SELECTED_TOP [UIColor colorWithRed:138.0/255.0 green:178.0/255.0 blue:154.0/255.0 alpha:1]
#define GRADIENT_SELECTED_BOTTOM [UIColor colorWithRed:114.0/255.0 green:171.0/255.0 blue:156.0/255.0 alpha:1]
- (void)drawRect:(CGRect)rect
{
[_gradientLayer setColors:#[(id)[GRADIENT_TOP CGColor],(id)[GRADIENT_BOTTOM CGColor]]];
[_glossyLayer setColors:#[(id)[GLOSS_TOP CGColor], (id)[GLOSS_BOTTOM CGColor]]];
[super drawRect:rect];
}
Finally, and the bit we've all been waiting for, override -(void)setHighlighted:(BOOL)highlighted{
so we can apply the highlight effect were looking for.
-(void)setHighlighted:(BOOL)highlighted{
[super setHighlighted:highlighted];
if(highlighted)
[_gradientLayer setColors:#[(id)[GRADIENT_SELECTED_TOP CGColor],(id)[GRADIENT_SELECTED_BOTTOM CGColor]]];
else
[_gradientLayer setColors:#[(id)[GRADIENT_TOP CGColor],(id)[GRADIENT_BOTTOM CGColor]]];
}
There we have it, now just drag out a UIButton modify the class and your all good. Heres the full Implementation so you can copy it straight out. http://pastebin.com/nUVeujyp
Check out the UIButton Class Reference.
Regular UIButtons do not have the backgroundColor option.
My suggestion would to use the UISegmentedControl, which has the tinColor option.
I have created a subclass which get background color and creates an UIImage for each state.
For me it's more useful a subclass instead a category, so that's up to you.
#implementation ROCRoundColorButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIColor *darkColor;
darkColor = [self darkColorFromBackgroundColor];
[self setBackgroundImage:[self imageWithColor:self.backgroundColor withSize:self.frame.size] forState:UIControlStateNormal];
[self setBackgroundImage:[self imageWithColor:darkColor withSize:self.frame.size] forState:UIControlStateSelected];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
UIColor *darkColor;
darkColor = [self darkColorFromBackgroundColor];
[self setBackgroundImage:[self imageWithColor:self.backgroundColor withSize:self.frame.size] forState:UIControlStateNormal];
[self setBackgroundImage:[self imageWithColor:darkColor withSize:self.frame.size] forState:UIControlStateSelected];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#pragma mark -
#pragma mark Private methods
- (UIColor *)darkColorFromBackgroundColor
{
const float* components = CGColorGetComponents( self.backgroundColor.CGColor );
CGFloat red = components[0];
CGFloat green = components[1];
CGFloat blue = components[2];
CGFloat alpha = components[3];
if (red > 0) {
red -= 0.1;
}
if (green > 0) {
green -= 0.1;
}
if (blue > 0) {
blue -= 0.1;
}
UIColor *darkColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
return darkColor;
}
- (UIImage *)imageWithColor:(UIColor *)color withSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
//CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, size.width, size.height) cornerRadius:5];
[roundedRect fillWithBlendMode: kCGBlendModeNormal alpha:1.0f];
[color setFill];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
In fact, you can use it in the storyboard, changing the class and setting de background color in the view.

how to change navigation bar background image manually in specific ViewController?

i'm trying to change the image background of my navigationbar when i'm in specific ViewController. My app model :
- appDelegate
- tabbarcontroller
-viewcontroller1
-navigationBarController
-viewcontroller2
-viewcontroller3 (*)
-viewcontroller4
-viewcontroller5
I've already implemented this code in appDelegate :
static NSMutableDictionary *navigationBarImages = NULL;
#implementation UINavigationBar(CustomImage)
+ (void)initImageDictionary
{
if(navigationBarImages==NULL){
navigationBarImages=[[NSMutableDictionary alloc] init];
}
}
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor blackColor];
NSString *imageName=[navigationBarImages objectForKey:[NSValue valueWithNonretainedObject: self]];
if (imageName==nil) {
imageName=#"navbar.png";
}
UIImage *image = [UIImage imageNamed:imageName];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.tintColor = color;
}
- (void)setImage:(UIImage*)image
{
[navigationBarImages setObject:image forKey:[NSValue valueWithNonretainedObject: self]];
}
#end
after that, i wrote this code in my viewcontroller2 :
[UINavigationBar initImageDictionary];
it's work, my navigation bar is like i wished, however in my viewcontroller3, i wrote :
UIImage *navBarLandscape = [UIImage imageNamed:#"navbar.png"];
[[[self navigationController] navigationBar] setImage:navBarLandscape];
and it doesn't do the trick, i have an error that i can't undertand :
[UIImage length]: unrecognized selector sent to instance 0x5a58130
2010-11-18 18:02:37.170 finalAudi[1463:307] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImage length]: unrecognized selector sent to instance 0x5a58130'
Do you have an idea?
regards polo.
In each viewController's viewDidLoad try:
/* make sure that we set the image to be centered */
/* you will ahve to make minor adjustments depending on the dimensions of your image. */
UIImageView *logo = [[UIImageView alloc] initWithFrame:CGRectMake(self.navigationController.navigationBar.frame.size.width/2-75,0,150,
self.navigationController.navigationBar.frame.size.height-1)];
[logo setImage:[UIImage imageNamed:#"myImage.png"]];
[self.navigationController.navigationBar addSubview:logo];
[self.navigationController.navigationBar sendSubviewToBack:logo];
and for viewWillAppear: and viewDidDisappear: try:
/* This will ensure that if you have a different image for each view that the previous viewController's navBar image wont stay. */
-(void)viewWillDisappear:(BOOL)animated {logo.hidden = YES;}
-(void)viewWillAppear:(BOOL)animated {logo.hidden = NO ;}
and to make sure that the image stays centered when rotating:
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight))){
[logo setFrame:CGRectMake(self.navigationController.navigationBar.frame.size.width/2-75,0,150,self.navigationController.navigationBar.frame.size.height-1)];
}else if(((interfaceOrientation == UIInterfaceOrientationPortrait) ||
(interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown))){
[logo setFrame:CGRectMake(self.navigationController.navigationBar.frame.size.width/2-80,0,150,self.navigationController.navigationBar.frame.size.height-1)];
}
}
thank's to all of you, i was able to fix my problem with this code in appdelegate:
#implementation UINavigationBar(CustomImage)
+ (void)initAppDelegate
{
if (applicationDelegate==Nil) {
applicationDelegate = (finalAudiAppDelegate *)[[UIApplication sharedApplication] delegate];
}
}
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor blackColor];
[[[applicationDelegate backNavBar] objectAtIndex:[applicationDelegate indexBackNavBar]] drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.tintColor = color;
}
#end
i'm using one NSMutableArray to stock my navigationBar's background images and one NSInteger (indexBackNavBar), i'm access to them with UIApplication sharedApplication.
Then in my viewcontroller, i just set indexBackNavBar = 1 in viewWillAppear and indexBackNavBar = 0 in viewWillDisappear. Voila!
If I understand correctly, I would recommend looking at the UINavigationBarDelegate and implementing the code to switch the background of the navigation bar there, instead of spreading it across multiple viewControllers.
The delegate has methods that will get called before pushing and popping new views so it might be better from a design perspective