TThree20: A Brief TTLauncherView tutorial

10/19/2010 § 35 Comments


The TTLauncherView is a very simple UI component in the sense of use, that basically mimics the iOS home screen. It comes with a scroll view and a page control that enables you to browse through a set of TTLauncherItems. Each of these items can be reordered, deleted or even have a badge number, just like application badges on the iOS home screen.

I already worked on a lot of applications that having a “home screen behavior” would be great. The Facebook guys found a very neat way to provide this behavior for custom application developers. They just made it a UI component with some delegate methods, just like every other standard component and of course, it works pretty well with their navigation model.

It is so simple, that you just have to create your view controller, append a TTLauncherView to it and attach your TTLauncherItems. If you want to provide a more complete behavior, just implement the TTLauncherViewDelegate and there you go.

Let’s see how to do it.

First of all, let’s create a UIViewController and name it LauncherViewController. Once you are done with it, modify the AppDelegate so that we map a TTURL to our view controller.


- (void)applicationDidFinishLaunching:(UIApplication *)application {
   TTNavigator* navigator = [TTNavigator navigator];
   navigator.persistenceMode = TTNavigatorPersistenceModeAll;
   TTURLMap* map = navigator.URLMap;
   [map from:@"*" toViewController:[TTWebController class]];
   [map from:@"tt://launcher/" toViewController:
       [LauncherViewController class]];

   if (![navigator restoreViewControllers]) {
      [navigator openURLAction:
       [TTURLAction actionWithURLPath:@"tt://launcher"]];
   }
}

Now if you run the app you should see a black screen with a navigation controller.

In order to properly display our view controller we need to make it present our Launcher view. The best method to work on this probably is the loadView method since we want to create a UILauncherView and nothing more.

LauncherViewController.m


- (void)loadView {
   [super loadView];
   TTLauncherView* launcherView = [[TTLauncherView alloc]
          initWithFrame:self.view.bounds];
   launcherView.backgroundColor = [UIColor blackColor];
   launcherView.columnCount = 4;
   launcherView.pages = [NSArray arrayWithObjects:
     [NSArray arrayWithObjects:
         [self launcherItemWithTitle:@"Google"
              image:@"bundle://safari_logo.png"
                 URL:@"http://google.com"],
        [self launcherItemWithTitle:@"Apple"
              image:@"bundle://safari_logo.png"
                 URL:@"http://apple.com"]
        , nil]
    , nil];

    [self.view addSubview:launcherView];
    [launcherView release];
}

You could add this code to the viewDidLoad method as well since we need the root view to have it’s frame properly set.

As you can see, when a launcher view is created all you need to do is to provide the proper launcher items that will be displayed and column count. Please note that the column count has nothing to do with the number of pages, which is equal to the number of arrays inside the array provided to the pages property.

Ideally you would read those launcher items from a local stored database (like NSUserDefaults) or even from asynchronously. In the first case, I suggest you to use the viewDidLoad method to set the pages property. In the second one, well it would be when the data is fetched 🙂

….

I know I know, your code is not compiling yet because there is a method missing. It is below, don’t panic.


- (TTLauncherItem *)launcherItemWithTitle:(NSString *)pTitle
       image:(NSString *)image URL:(NSString *)url {
    TTLauncherItem *launcherItem = [[TTLauncherItem alloc]
          initWithTitle:pTitle
          image:image
         URL:url canDelete:YES];
    return [launcherItem autorelease];
}

Now you can run the app and see a not that nice “home screen like” view controller. If you have an image to use in place of safari_logo.png, feel free to try it. Otherwise just download the full source code here.

You will notice that if you press and hold a launcher item, all badges will start to wiggle just like the iOS home screen. You can also reorder and delete it. But you can’t cancel the edit mode, because you will send your app to the background if you tap on the Home Button.

Let’s fix this issue by using a Edit/Done button on the navigation bar, just like every iOS app does (you can think of a better way once you learn how it works :] ).


- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"My Launcher View";
    UIBarButtonItem *editButton = [[UIBarButtonItem alloc]
         initWithBarButtonSystemItem:UIBarButtonSystemItemEdit
         target:launcherView     action:@selector(beginEditing)];
    self.navigationItem.rightBarButtonItem = editButton;
    [editButton release];
}

Now we should handle TTLauncherView editing states so that when you tap on Edit, it changes to Done and the TTLauncherView becomes editable. If you tap Done, it stops being editable and the button changes back to Edit. To really be consistent, let’s change Edit to Done when the TTLauncherView becomes editable but the user did not tap on Edit. So, modify your loadView method to set the TTLauncherView delegate property to self and append the following TTLauncherViewDelegate methods to our controller.


- (void)launcherViewDidBeginEditing:(TTLauncherView*)launcher {
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]
       initWithBarButtonSystemItem:UIBarButtonSystemItemDone
       target:launcherView action:@selector(endEditing)];
    self.navigationItem.rightBarButtonItem = doneButton;
    [doneButton release];
}

- (void)launcherViewDidEndEditing:(TTLauncherView*)launcher {
    UIBarButtonItem *editButton = [[UIBarButtonItem alloc]
         initWithBarButtonSystemItem:UIBarButtonSystemItemEdit
         target:launcherView action:@selector(endEditing)];
    self.navigationItem.rightBarButtonItem = editButton;
    [editButton release];
}

Run the app and try out our modifications.

Ok it is working pretty fine…but our launcher stills not able to launch anything 🙂 This is a easy fix.


- (void)launcherView:(TTLauncherView*)launcher
       didSelectItem:(TTLauncherItem*)item {
    [[TTNavigator navigator] openURLAction:
      [TTURLAction actionWithURLPath:item.URL]];
}

Hope you enjoyed this brief tutorial. Now it is time for you to improve this sample code and make a nice app!

Tagged: , , , , ,

§ 35 Responses to TThree20: A Brief TTLauncherView tutorial

  • Ashutosh Joshi says:

    hey thanks a ton for this tutorial.
    However, I am still confused as to how I would launch say a UIVIEWController when an item is selected. I tried looking around but to no avail.
    Kinda like Facebook and Grooveshark app. Clicking one of the items opens up a view controller and the left nav button changes to point to home(launcher screen)
    Can you shed some light on that?

    • Hi Joshi,

      when an item is selected the launcherView:didSelectItem: is called. When this happens you can open a TTURL that is actually mapped to your view controller (in your app delegate).

      Meaning that you can get the code provided on this tutorial, changing the current URL to one that you mapped (like tt://myViewController) just like I am doing on the applicationDidFinishLaunching method (the very first method from this tutorial shows how to map a TTURL to a custom view controller).

      Then you can have you view controller to change the nav bar button state as you would normally do (without Three20).

      Thanks for feedback!

  • edd says:

    thanks, the last bit helped me alot, i have been stuck with this thing for the whole day!! cheers

  • kimti says:

    hi man, i want to know the window how to init in your TTLauncherView demo,i see the “openURLAction:” method ,it mean follow:

    /**
    * Load and display the view controller with a pattern that matches the URL.
    *
    * This method replaces all other openURL methods by using the chainable TTURLAction object.
    *
    * If there is not yet a rootViewController, the view controller loaded with this URL
    * will be assigned as the rootViewController and inserted into the keyWindow. If there is not
    * a keyWindow, a UIWindow will be created and displayed.
    *
    * Example TTURLAction initialization:
    * [[TTURLAction actionWithURLPath:@”tt://some/path”]
    * applyAnimated:YES]
    *
    * Each apply* method on the TTURLAction object returns self, allowing you to chain methods
    * when initializing the object. This allows for a flexible method that requires a shifting set
    * of parameters that have specific defaults. The old openURL* methods are being phased out, so
    * please start using openURLAction instead.
    */

    but i don’t know how it init the window,can you help me?
    thank you.

    • I am not sure what you meant. Do you want to create a window by yourself? That is probably a bad idea.

      When it comes to iPhone, we usually want to keep only one window for the whole app. It is much more difficult to place components and arrange UI on a UIWindow, since the coordinate system is not the same.

  • Mike says:

    Hi,

    Thank you very much for this code, it was quite helpful! However I’m still not able to load a custom controller. Maube you can provide some help here.

    I added this to didFinishLaunchingWithOption:

    [map from:@”tt://helloWorld/(initWithName:)” toSharedViewController:[HelloWorldController class]];

    This should map to my HelloWorldController class, calling initWithName: method.
    Debugging I can see that this method is called, but the view associated with my controller is not called. Is there something else I have to do? Do I need to push the view manually? I’m still somehow confused with this.

    Thank you very much

    • Mike says:

      By the way, if I map the controller without a method, it works great, and the view is pushed. If I map with a method, it does call the method but it does not push :S

    • Hmmm…I had no problems with that.

      What you can do is to implement the delegate to decide where to push the view (push via navigation controller or place inside another view or even display as a popover).

  • surabhi says:

    Hi,

    I was working on TTLauncherView. I am a newbie to three20.
    When I change the position of items, they change. But when I close the application and restart again, the changed items positions do not save.

    DO you know how to do that??
    Please help.

    • Your loadView must be running again and reseting the pages property (if your code is the same presented on this tutorial).

      You just have to make sure the value you assign to “pages” is the ordered one.

  • Marvin says:

    Hello,
    its possible to get a Sample Project via eMail ?

    Thanks a lot

  • Luigi says:

    Hi Cezar,
    thank you for this tutorial.
    I’ve implemented TTLauncher successfully, but I have now an issue.

    If I have a map in this way:

    [map from:@”tt://onlineCall/(callOnlineURL:)” toViewController: [myCustomWebController class]];

    and i click on my item,
    i see (with NSLog) that the method “callOnlineURL” is called correctly… but the view of myCustomWebController doesn’t show … instead if i change map with no calling methods… my view appear correctly.
    How I can call “viewDidLoad” after “callOnlineURL” is called ?

    thanks for help (and sorry for my bad english 😉 )

    • Hey!

      Check your implementation for the TTNavigationDelegate:

      – (BOOL)navigator:(TTBaseNavigator*)navigator shouldPresentURL:(NSURL*)URL;
      – (BOOL)navigator:(TTBaseNavigator *)navigator shouldOpenURL:(NSURL *)URL;
      – (void)navigator:(TTBaseNavigator*)navigator willOpenURL:(NSURL*)URL inViewController:(UIViewController*)controller;

      You may want to push your controller using willOpenURL (and returning NO for the first method and YES for the second).

      Good luck!

      • Luigi says:

        thank you Cezar,
        you pointed me to the right direction !

        But for now… this approach does not work.
        In your opinion … if I have a UIView Controller with a NSString *urlToGO (controlling a WebView which load with this string) … how i can modify urlToGo and display the view with TTLauncher ?

        Thanks a lot for help

  • Bhavesh says:

    Three20 Save Rearranging launcher item

    I currently attached Three20 to my XCode project.
    I Load it on my button click of firstviewcontroller using
    pushviewcontroller.
    When Launcher view is loaded i enter in to the edit mode of launcher
    view, after that i rearrange launcher items.
    After this i go back to my firstviewcontroller .
    but when i return again to launcher view the launcher items are not in
    the rearranged position.They are in same as it loaded at first
    time.
    So any one have idea how can i save rearranged state of my launcher
    view.
    Please send me solution i am eagerly waiting for solution.

  • Riaz says:

    Hi,

    Thanks for your tutorial with which we learnt a lot.

    We have a requirement where touching a button-image of an initial LauncherView
    goes to a second LauncherView.

    We tried it and it kind of works but the app crashes after returning to the initial
    LauncherView esp. when we try to navigate again on the initial LauncherView.

    Does Three20 LauncherView support more than one TTLauncherView?

    Thanks for your help.
    Riaz

  • Thijs Bastiaens says:

    Hey 🙂

    I’m not getting this to work anymore, everything worked perfectly fine, and I started it again next morning, and bam, blackout.
    Only white screen, it’s loading everything in the background, and I can click buttons on the background.. but, not working. Downloaded ur example app, but it’s missing all the Three20 import’s etc. So can’t build that >.<

    Any chance u mind emailing me?

  • Thanks so much for this tutorial!! I was having trouble getting used to Three20 but this tutorial has helped me a lot.

  • Harry says:

    Cheers Cezar, really useful.

  • mubashir says:

    i have a question, what we have to do for including three20 library. Its giving error ‘three20.h No such file or directory’.

    plz help.

    • mubashir says:

      when i run the code downloaded from site it works perfect, but then i created a new project and included three20 library through python script and copied the code given in tutorial, but then its not working, its showing only white blank screen.

  • Really usefull. Thanks so much!!! Really has helped me a lot.

  • I think this line is missing in the application:didFinishLaunchingWithOptions function

    navigator.window = window;

    Without this line, the view was blank. And when I added it, it worked perfectly.

  • Umar says:

    Hi,
    Very nice tutorial. How can we animate the Launcher View item? Lets say I tap on one item and i want to move the item 5px up. How can we do that?

  • amy says:

    thanks a lot…its really good tutorial….

    if i want to Alert a user first when they push a delete item… how can i do that ???

    Thanks

    • Hi,

      I dont think you can do that out-of-the-box, since it is not expected behavior.

      But you should take a look on the delegate and navigation schema to see if you find a good solution to your problem.

  • Shonak Nathwani says:

    Hi Umar,

    Great tutorial, but I’m new to the Three20 Framework and I’d really appreciate it if you could send me the sample project.

    Thanks in advance,

    Shonak

Leave a reply to Harry Cancel reply

What’s this?

You are currently reading TThree20: A Brief TTLauncherView tutorial at iOS Guy.

meta