Tag Archive > iPhone

Customizing the UINavigationController

Ricki » 16 June 2010 » In Cocoa Touch, Objective C » 1 Comment

I had to add some new tags to my blog as the content will mostly be Cocoa Touch, Objective C, iPhone stuff from now on.

I think the UINavigationController is by far the most widely used Controller-controller.

Out of the box the API’s for customizing the looks of the UINavigatioController are limited to setting a tint for the background color.

I am doing an iPhone app and I would like to have the freedom to set the title label, the color, background image and the buttons to whatever I like. I, however, do not want to get rejected by the App Store approval process or implement my own controller, so in this post I’ll deliver some Proof-of-Concept code for how to do this.

The product:

Yes you are a pretty girl..

The finished product

The caveats:

There are two different approaches involved: one is to build a category on the UINavigationBar, which is the view of the UINavigationController, to set the background to either a static color or a custom image. The other approach is to build a utility Class with one class method that alters the the look of a UIViewControllers UINavigationController. Notice that I wrote that we alter the look of the UINavigationController for each ViewController. There are caveats involved! This is just a Proof of Concept (feel free to add to the code and feel especially free to show me afterwards).

  • It does not support rotation!
  • The size of the navigationBar buttons are fixed’!
  • The background color/image for the UINavigationBar can not be changed at runtime.
  • You need to implement a tap handler method to catch the actions from the buttons on the navigationBar.

Probably other things… but it can be added and maybe it will.

The code:

First off, let’s construct a category for the UINavigationBar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
//  UINavigationBar+customLook.h
//  UINavigationBarOverrideDrawRectPOC
//
//  Created by Ricki Gregersen on 14/6/10.
//  Copyright 2010 www.rickigregersen.com. Use as you please:)
//

#import

@interface UINavigationBar (customLook)

- (void) drawRect:(CGRect)rect;

@end

And the implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import "UINavigationBar+customLook.h"

@implementation UINavigationBar (customLook)

- (void)drawRect:(CGRect)rect {

/* comment in this part to use a color instead of an image
    UIColor *color = [UIColor redColor];
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColor(context, CGColorGetComponents( [color CGColor]));
    CGContextFillRect(context, rect);
    self.tintColor = [UIColor darkGrayColor];// color;
*/

// comment out this part to use a color instead of an image
    UIImage *img    = [UIImage imageNamed: @"nav_bar_back.png"];
    [img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}

@end

The drawRect method is invoked every time a UIViewController is pushed onto the screen. You could therefore make global variable that held a reference to the image or color if you needed it to change at runtime.

Now onto the the UINavigaitonModifier Class. This contains one class method that takes a UIViewController, a title string for the left and right button, and a boolean for the left and right button determining if it is a square or an “arrow”. (the usual back button is an arrow). The class also defines a protocol for receiving actions when either button is tapped.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//  ISNavigationModifier.h
//  UINavigationBarOverrideDrawRectPOC
//
//  Created by Ricki Gregersen on 14/6/10.
//  Copyright 2010 www.rickigregersen.com. Use as you please:)
//

#import

@protocol ISNavigationModifierProtocol

@optional

- (void) leftBarButtonHandler:(id) sender;
- (void) rightBarButtonHandler:(id) sender;

@end

@interface ISNavigationModifier : NSObject {

}

+ (void) modifyNavigationBarFor:(UIViewController*) target : (NSString*) leftButtonString : (BOOL) isLeftArrow : (NSString*) rightButtonString : (BOOL) isRightArrow;

@end

The implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//  ISNavigationModifier.m
//  UINavigationBarOverrideDrawRectPOC
//
//  Created by Ricki Gregersen on 14/6/10.
//  Copyright 2010 www.rickigregersen.com. Use as you please:)
//

#import "ISNavigationModifier.h"

@implementation ISNavigationModifier

+ (void) modifyNavigationBarFor:(UIViewController*) target : (NSString*) leftButtonString : (BOOL) isLeftArrow : (NSString*) rightButtonString : (BOOL) isRightArrow {

    UIButton *rightButton = nil;
    UIButton *leftButton = nil;

    if (leftButtonString) {

        leftButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [leftButton addTarget:target action:@selector(leftButtonHandler:) forControlEvents:UIControlEventTouchUpInside];
        [leftButton.titleLabel setFont:[UIFont fontWithName:@"Thonburi-Bold" size:12]];
        [leftButton setTitle:leftButtonString forState:UIControlStateNormal];

        if (isLeftArrow) {
            [leftButton setFrame:CGRectMake(0.0f, 0.0f, 79.0f, 37.0f)];
            [leftButton setBackgroundImage:[UIImage imageNamed:@"arrow_square_btn.png"] forState:UIControlStateNormal];
        } else {
            [leftButton setFrame:CGRectMake(0.0f, 0.0f, 79.0f, 37.0f)];
            [leftButton setBackgroundImage:[UIImage imageNamed:@"square_btn.png"] forState:UIControlStateNormal];
        }
   }

    if (rightButtonString) {

        rightButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [rightButton addTarget:target action:@selector(rightButtonHandler:) forControlEvents:UIControlEventTouchUpInside];
        [rightButton.titleLabel setFont:[UIFont fontWithName:@"Thonburi-Bold" size:12]];
        [rightButton setTitle:rightButtonString forState:UIControlStateNormal];

        if (isLeftArrow) {
            [rightButton setFrame:CGRectMake(0.0f, 0.0f, 79.0f, 37.0f)];
            [rightButton setBackgroundImage:[UIImage imageNamed:@"arrow_square_btn.png"] forState:UIControlStateNormal];
        } else {
            [rightButton setFrame:CGRectMake(0.0f, 0.0f, 79.0f, 37.0f)];
            [rightButton setBackgroundImage:[UIImage imageNamed:@"square_btn.png"] forState:UIControlStateNormal];
        }
    }

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 150.0f, 20.0f)];
    [label setFont:[UIFont fontWithName:@"Thonburi-Bold" size:14]];
    [label setBackgroundColor:[UIColor clearColor]];
    [label setTextAlignment:UITextAlignmentCenter];
    [label setText:target.title];
    [target.navigationItem setTitleView:label];
    [label release];

    UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithCustomView:leftButton];
    UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithCustomView:rightButton];
   
    [target.navigationItem setLeftBarButtonItem:leftItem];
    [target.navigationItem setRightBarButtonItem:rightItem];

    [leftItem release];
    [rightItem release];
}

@end

The modifier class uses the reference to the UIViewController to change the navigationBar.

Example:

To use the above classes; put the UINavigationBar+customLook.h and UINavigationBar+customLook.m files somewhere in your project. Change the images or color property to fit your custom style.
Also add the ISNavigationModifier.h and ISNavigationModifier.m.
In a viewController that is pushed onto a NavigationController; import the ISNavigationModifier.h file, implement the methods: leftButtonHandler and rightButtonHandler.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void) viewDidLoad {

    [super viewDidLoad];
    self.title = @"I am a pretty girl";
    [ISNavigationModifier modifyNavigationBarFor:self :@"Back" :NO :@"Next" :NO];
}

- (void) leftButtonHandler:(id) sender {

    [self.navigationController popViewControllerAnimated:YES];
    NSLog(@"Left Button Tapped!");
}
- (void) rightButtonHandler:(id) sender {

    ISViewControllerThree *vcThree = [[ISViewControllerThree alloc] initWithNibName:@"ISViewControllerThree" bundle:nil];
    [self.navigationController pushViewController:vcThree animated:YES];
    [vcThree release];
    NSLog(@"Right Button Tapped!");
}

Feel free to put  rants, comments, questions and improvements in the comments below.

Continue reading...

Tags: , , ,

No More Virtual Machines

Ricki » 17 January 2010 » In Objective C, iPhone » No Comments

Sorry for the 3 month dry streak.

I was fired back in, think it was August? :) . I then had a three month “paid vaccination”(it was in my contract that in the event I was fired they had to pay me for 3 months but I didn’t have to come to work…sweet). Did some consulting work, mostly to have something to do. Then I thought to my self that this was an excellent time to set a dream of mine in motion. I come from a background in computer and electronic engineering.

In my Flash/Java work I always had this strange feeling in the back of my head going “At some point this is going to break or perform strangely, and I have no way, other that trial and error, to figure out why”. This is harshly put, but I have been used to dealing with µControllers, the C language and copper-wire  for a long time and even though I appreciate things that “just work” as much as the next guy, I also feel the complete despair when it does not and you have no way of getting “under the hood”.

Im probably being ignorant and if I would I could sit down and read up on every nook and cranny of the runtime, then I would be the all-omnipotent, all-mighty and know-it-all master of… a nook.

My previous job involved building Flash apps for the AIR  runtime environment, I know, I know, that is asking for trouble(2007-2009), and my only real choice of an editor was Eclipse. Im a Mac user and that just “grinds my gears” to have to use some “lowest common denominator” GUI for what I do with most of the hours Im awake.

I have a duality in my that dictates that I love building stuff for the internal intricacies and that I only can enjoy software, furniture, food TV series etc. if I know the order and beauty that governs the inside also governs the outside, i.e. I like good design on both the inside and the outside.

So how do I get to work with µControllers and hardware, beautiful interfaces and have a set of development tools that doesn’t hate me and gives me a stack dump when I ask for it?

I have become an iPhone developer!

OK, plan… by rationing my means I can sustain myself for almost a year. In that timeframe I should be able to (a) learn Objective C (b) get a few apps in the store (c) go down new roads and be happy:)

So for the last three months I have been developing an app that will _blank_ for _blank_ when you go _blank_, with a designer called Mino, which is a secretive guy, hence the _blank_ :)

Now we are close to a Beta version and I my head is exploding with pieces of info that I would like to put on the blog. Im at the state of learning a new language where I bought the first “pattern book”, which means I did a lot of “ahh this seems to be the way to go” only to go “ahh so that is how I should have done it” a few hours later. Well, to cut it short, I don’t think there will be a lot of AS – Java stuff on the blog in the time to come, but I hope to keep doing the visual experiments and give out some code snippets.

I’ll surely move on to building some Mac software afterwards, I like the tools, the Apple frameworks has the standard of the Apple hardware (95% perfect and 5% “WTF, this took me forever and now it’s broken again”) also I get the “complete package experience” that I was missing in my other endeavors.

So please spread the word that Im up for crazy and exciting projects, both here in DK and abroad.

Continue reading...

Tags: ,