Thursday, October 21, 2010

Sizing a launcher item image in Three20

Recently I got deeper into iPhone (or iOS) programming, doing some projects for fun and for fee.
My friend Reuven wanted me to use a framework called Three20 in the context of a project I am doing for XMPie, but the person who really pushed me into it is Yosi Taguri of who gave me a crash course on Three20.
So, I am working now on converting the XMPie project to Three20, and I spent the last couple of hours on trying to get the launcher view work with some images that are of unknown sizes. I initially thought I will have to sub-class the launcher view and all its related classes (TTLauncherItem, TTLauncherButton), but this is of course the wrong way of doing things in Three20...
There is a better way which is to use the stylesheet mechansim of Three20. I read the tutorial by Matt Vague (Three20 stylesheets tutorial), but it was not enough to get what I wanted.
What really helped me figure this one out is a tool named TTStyleBuilder by a guy named Keith Lazuka.
finally I was able to create the following style in my stylesheet to get the images to behave:

- (TTStyle*)launcherButtonXM:(UIControlState)state {
    [TTPartStyle styleWithName:@"image" style: TTSTYLESTATE(launcherButtonImageXM:, state) next:
     [TTTextStyle styleWithFont:[UIFont boldSystemFontOfSize:11] color:RGBCOLOR(180, 180,180)
                minimumFontSize:11 shadowColor:nil shadowOffset:CGSizeZero
                  textAlignment:UITextAlignmentCenter verticalAlignment:UIControlContentVerticalAlignmentBottom
                  lineBreakMode:UILineBreakModeClip numberOfLines:1 next:nil]];

// Our launcher button image style
- (TTStyle*)launcherButtonImageXM:(UIControlState)state {

    TTStyle* style =
     [TTShapeStyle styleWithShape:[TTRoundedRectangleShape
                                   shapeWithRadius:8] next:
      [TTBoxStyle styleWithMargin:UIEdgeInsetsMake(0, 0, 0, 0)
                          padding:UIEdgeInsetsMake(22, 22, 22, 22)
                          minSize:CGSizeMake(0, 0)
                         position:TTPositionStatic next:
          [TTImageStyle styleWithImageURL:nil defaultImage:nil contentMode:UIViewContentModeScaleAspectFit
                                     size:CGSizeMake(57, 57) next:nil

    if (state == UIControlStateHighlighted || state == UIControlStateSelected) {
        [style addStyle:
         [TTBlendStyle styleWithBlend:kCGBlendModeSourceAtop next:
          [TTSolidFillStyle styleWithColor:RGBACOLOR(0,0,0,0.5) next:nil]]];
    return style;

You use this style in the launcher by setting the style property of the launcher item: = @"launcherButtonXM:";
        [_launcherView addItem:launcherItem animated:YES];

Three20 is cool!

[Edit] Based on some questions I got, I want to clarify that the style methods above are placed in my XMDefaultStyleSheet which is defined as an inherited class of TTDefaultStyleSheet. I create an instance of this class and set it as the default style sheet in the App Delegate applicationDidFinishLaunching method like that:

    // register our stylesheet
    [TTStyleSheet setGlobalStyleSheet:[[[XMPDefaultStylesheet alloc] init] autorelease]];


  1. hey,

    I was looking for this information and found your blog. Thanks for this information. However I had a question.

    Did you subclass TTDefaultStyleSheet to achieve this result? Can you show me a sample script that you used?


  2. I sub-classed the default style sheet and added those to my stylesheet, then added to the appdelegate the follwoing code in the applicationDidFinishLaunching method:

    // register our stylesheet
    [TTStyleSheet setGlobalStyleSheet:[[[XMPDefaultStylesheet alloc] init] autorelease]];

  3. Zafer - that's true. but not sure it will change the item size itself...

  4. There is a small issue with the stylesheet, is does not take into account the badges. Because we add padding, the badge gets set far away from the actual button.

    I'm looking into it :)