Three20 Tutorial for iOS

A Three20 tutorial for iOS introducing the Three20 library for iOS – an open source library of handy controls. By Ray Wenderlich.

Leave a rating/review
Save for later
Share

Character Viewer we'll make using Three20

Character Viewer we'll make using Three20

The Three20 Library is a great open source library for the iPhone developed by Joe Hewitt, the developer of the Facebook iPhone app. The library is chock full of useful code for just about any iPhone project. It has an amazing image browser, great asynchronous/web loading support, stylizable views and labels, and a ton more.

In fact, the library is so full of useful stuff that it can be a little difficult getting a handle on it at first. Since I’m just getting started with Three20 myself, I thought I’d write up a Three20 tutorial to show a few basic features of Three20 to other newcomers.

In this Three20 tutorial, we’ll be making is a viewer for a list of characters you might have in a tabletop RPG. The Three20 tutorial will show you how to integrate Three20 into your projects and give you an introduction to two important components in Three20: URL navigation and custom views.

Adding Three20 To Your Project

Create a new project in XCode by going to File\New Project, and select Window-based Application. Click Choose, and name the Project “RPGChars.”

Next you need to get a copy of the three20 library. The best way to get the latest copy of three20 is to use the source control system “git.” If you do not already have this installed, you can download a Mac installer.

Once you have git installed, follow the excellent instructions on the three20 web page for instructions on how to pull down the latest code and add it to your project.

Once you’ve done that, add the following to the top of RPGCharsAppDelegate.h:

#import "Three20/Three20.h"

Compile your project – if it works three20 has been successfully integrated and you can move onto the next step!

Listing Our Characters

The first thing we’re going to do is to add a table view to list our RPG characters.

However before we begin we’re going to need to create some classes to model our characters. Creating a model for the characters has nothing to do with Three20 so isn’t important for the sake of this Three20 tutorial, so just download a set of RPG character classes that I made and add them into your project.

Then, right click on Classes and select Add\New File, and select Cocoa Touch Class\Objective-C class\Subclass of NSObject, and name the new file CharacterListController.m (and make sure “Also create CharacterListController.h” is checked), and click “Finish”. Then replace the contents of CharacterListController.h with the following:

#import <Three20/Three20.h>

@interface CharacterListController : TTTableViewController {

}

@end

Here we are creating a subclass of TTTableViewController, Three20’s version of UITableViewController and importing the Three20 header.

Now replace the contents of CharacterListController.m with the following:

#import "CharacterListController.h"
#import "CharacterData.h"
#import "Character.h"

@implementation CharacterListController

- (id)initWithNavigatorURL:(NSURL*)URL query:(NSDictionary*)query {
    
    if (self = [super init]) {
        
        self.tableViewStyle = UITableViewStyleGrouped;
        self.title = @"Characters";
        
        TTListDataSource *dataSource = 
            [[[TTListDataSource alloc] init] autorelease];
        
        NSMutableArray *characters = 
            [[CharacterData sharedCharacterData] characters];
        for(int i = 0; i < [characters count]; i++) {
            
            Character *character = (Character *) [characters objectAtIndex:i];
            
            TTTableItem *tableItem = 
                [TTTableSubtitleItem 
                    itemWithText:character.name
                    subtitle:[NSString stringWithFormat:@"Level %d %@", 
                        character.level, character.rpgClassName]
                    URL:@""];
            
            [dataSource.items addObject:tableItem];
        }
        
        self.dataSource = dataSource;
        
    }
    return self;
    
}

Let's go through the above code step by step.

Note that the initializer is called initWithNavigatorURL:query rather than plain old init. This is because initWithNavigatorURL:query is the default initializer sent to a view controller, if you don't override it otherwise. If you make a mistake and use plain old init, you'll see a "loading" screen since your initializer will never get called.

The first thing we do is set the style and title of the table view. Then, we construct a class for the data source - in this case a TTListDataSource. There is also a TTSectionedDataSource that lets you group data easily into sections, but we don't need that in this case - a simple list will do.

We then loop through all of the characters in our model, and one by one we create a table item for them. Three20 comes with many useful table styles to use, and has one that works pretty well for our needs - a TTTableSubtitleItem, so we choose that.

Note that we leave the URL of the table item blank for now - we'll fill that in later.

Then we set the data source to the class we've been constructing, and that's it! This is literally all of the code we need to display our list of characters in a table view. You can already see how this is much less code than the standard code we'd use to write this.

Now let's get our app delegate to load up our view controller - by using Three20's URL navigation systmem.

Three20 and URL Navigation

In a bit we're going to want to modify our app so that when we tap on a character, it brings up a detail view for that character. Usually to implement this, you'd handle the didSelectRowAtIndexPath method in your table view, and then hard-code the construction of a detail view controller and push it onto the stack of the app's navigation controller.

Three20 adds a layer of abstraction into the mix by introducing the concept of URL navigation in an iPhone app. Instead of having to hard-code which navigation controller is responsible for the detail view, each cell can have an URL associated with it, and you can register which view controllers can handle which URLs.

The easiest way to explain this is to see it in code. We're going to set up URL based navigation for all of the view controllers in our app, but to get started we're going to start with the view controller we just made.

Open up RPGCharsAppDelegate.m and add the following import to the top:

#import "CharacterListController.h"

Then replace the applicationDidFinishLaunching method with the following:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

    TTNavigator *navigator = [TTNavigator navigator];
    navigator.window = window;
    
    TTURLMap *map = navigator.URLMap;
    [map from:@"tt://characterList" 
        toSharedViewController:[CharacterListController class]];
    
    [navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://characterList"]];
    
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

Here we create a new TTNavigator, which is the object that will handle the loading and displaying of our view controllers. We give it a handle to the main window, and we allow it to create a UINavigationController for us behind the scenes.

We then create a TTURLMap to set up the associations from URL to view controller. We say that whenever someone tries to navigate to the "tt://characterList" URL, that should load up the CharacteListController view controller.

And then we start the app off by launching that URL, which should then load up the CharacterListController - and that's it!

Compile and run the app, and if all looks well you should see a nice list of characters on the screen:

Screenshot of list of characters